Compare commits
11 Commits
@antv/x6@2
...
@antv/x6-s
Author | SHA1 | Date | |
---|---|---|---|
cdd0913eee | |||
a696009ede | |||
c808ca6d2b | |||
d3301d33d5 | |||
0029555458 | |||
cc18463c53 | |||
fb8098c1c0 | |||
c250caba6a | |||
019333d79d | |||
33c2e59207 | |||
844ee5fa04 |
@ -80,6 +80,7 @@ zdc1111 <39116292+zdc1111@users.noreply.github.com>
|
||||
€alix <qq287649920@gmail.com>
|
||||
九思⚡⚡⚡ <2228429150@qq.com>
|
||||
何腾飞 <avrin.live.cn@outlook.com>
|
||||
依枫 <deng25st@163.com>
|
||||
偏右 <afc163@gmail.com>
|
||||
小耀 <jinyue.gjy@antfin.com>
|
||||
崖 <bubkoo.wy@gmail.com>
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 12 MiB |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 Alipay.inc
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "x6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "node ./scripts/preinstall",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"lint:ts": "eslint '**/src/**/*.{js,ts}?(x)' --cache --fix",
|
||||
"lint:style": "stylelint '**/src/**/*.less' --customSyntax postcss-less --cache --fix",
|
||||
"lint": "run-s lint:ts lint:style",
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-plugin-transform [2.1.5](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.4...@antv/x6-plugin-transform@2.1.5) (2022-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add defense for view in transform plugin ([#3092](https://github.com/antvis/x6/issues/3092)) ([fb8098c](https://github.com/antvis/x6/commit/fb8098c1c06440dd69f4e93881fd36f7e6de2a56))
|
||||
|
||||
## @antv/x6-plugin-transform [2.1.4](https://github.com/antvis/x6/compare/@antv/x6-plugin-transform@2.1.3...@antv/x6-plugin-transform@2.1.4) (2022-12-07)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-plugin-transform",
|
||||
"version": "2.1.4",
|
||||
"version": "2.1.5",
|
||||
"description": "transform plugin for X6",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -107,7 +107,11 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
|
||||
|
||||
render() {
|
||||
this.renderHandles()
|
||||
this.view.addClass(Private.NODE_CLS)
|
||||
|
||||
if (this.view) {
|
||||
this.view.addClass(Private.NODE_CLS)
|
||||
}
|
||||
|
||||
Dom.addClass(this.container, this.containerClassName)
|
||||
Dom.toggleClass(
|
||||
this.container,
|
||||
@ -153,7 +157,9 @@ export class TransformImpl extends View<TransformImpl.EventArgs> {
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.view.removeClass(Private.NODE_CLS)
|
||||
if (this.view) {
|
||||
this.view.removeClass(Private.NODE_CLS)
|
||||
}
|
||||
return super.remove()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-vue-shape [2.0.9](https://github.com/antvis/x6/compare/@antv/x6-vue-shape@2.0.8...@antv/x6-vue-shape@2.0.9) (2022-12-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* get graph from right place ([#3078](https://github.com/antvis/x6/issues/3078)) ([844ee5f](https://github.com/antvis/x6/commit/844ee5fa043cbcd788ec1693f88576e797426228))
|
||||
|
||||
## @antv/x6-vue-shape [2.0.7](https://github.com/antvis/x6/compare/@antv/x6-vue-shape@2.0.6...@antv/x6-vue-shape@2.0.7) (2022-12-09)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6-vue-shape",
|
||||
"version": "2.0.7",
|
||||
"version": "2.0.9",
|
||||
"description": "X6 shape for rendering vue components.",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -26,6 +26,7 @@ export class VueShapeView extends NodeView<VueShape> {
|
||||
this.unmountVueComponent()
|
||||
const root = this.getComponentContainer()
|
||||
const node = this.cell
|
||||
const graph = this.graph
|
||||
|
||||
if (root) {
|
||||
const { component } = shapeMaps[node.shape]
|
||||
@ -40,13 +41,13 @@ export class VueShapeView extends NodeView<VueShape> {
|
||||
provide() {
|
||||
return {
|
||||
getNode: () => node,
|
||||
getGraph: () => this.graph,
|
||||
getGraph: () => graph,
|
||||
}
|
||||
},
|
||||
})
|
||||
} else if (isVue3) {
|
||||
if (isActive()) {
|
||||
connect(this.targetId(), component, root, node, this.graph)
|
||||
connect(this.targetId(), component, root, node, graph)
|
||||
} else {
|
||||
this.vm = createApp({
|
||||
render() {
|
||||
@ -55,7 +56,7 @@ export class VueShapeView extends NodeView<VueShape> {
|
||||
provide() {
|
||||
return {
|
||||
getNode: () => node,
|
||||
getGraph: () => this.graph,
|
||||
getGraph: () => graph,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6 [2.1.3](https://github.com/antvis/x6/compare/@antv/x6@2.1.2...@antv/x6@2.1.3) (2022-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* schedule edge when source and target is not ready ([#3090](https://github.com/antvis/x6/issues/3090)) ([019333d](https://github.com/antvis/x6/commit/019333d79d7f22c44c400f29d501497f4323af1a))
|
||||
|
||||
## @antv/x6 [2.1.1](https://github.com/antvis/x6/compare/@antv/x6@2.1.0...@antv/x6@2.1.1) (2022-12-19)
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@antv/x6",
|
||||
"version": "2.1.1",
|
||||
"version": "2.1.3",
|
||||
"description": "JavaScript diagramming library that uses SVG and HTML for rendering",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -219,6 +219,18 @@ export class Scheduler extends Disposable {
|
||||
|
||||
if (result) {
|
||||
console.log('left flag', result) // eslint-disable-line
|
||||
if (
|
||||
cell.isEdge() &&
|
||||
(result & view.getFlag(['source', 'target'])) === 0
|
||||
) {
|
||||
this.requestViewUpdate(
|
||||
view,
|
||||
result,
|
||||
options,
|
||||
JOB_PRIORITY.RenderEdge,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
24058
pnpm-lock.yaml
generated
24058
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
if (!/pnpm/.test(process.env.npm_execpath || '')) {
|
||||
console.warn(
|
||||
`This repository requires using pnpm as the package manager for scripts to work properly.`,
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
@ -12,7 +12,9 @@ if (window) {
|
||||
(window as any).x6PluginStencil = require('@antv/x6-plugin-stencil');
|
||||
(window as any).x6PluginHistory = require('@antv/x6-plugin-history');
|
||||
(window as any).x6ReactShape = require('@antv/x6-react-shape');
|
||||
(window as any).x6Common = require('@antv/x6-common');
|
||||
(window as any).layout = require('@antv/layout');
|
||||
(window as any).classnames = require('classnames');
|
||||
(window as any).hierarchy = require('@antv/hierarchy');
|
||||
(window as any).elkjs = require('elkjs/lib/elk.bundled.js');
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,10 @@
|
||||
## @antv/x6-sites [1.2.2](https://github.com/antvis/X6/compare/@antv/x6-sites@1.2.1...@antv/x6-sites@1.2.2) (2022-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* schedule edge when source and target is not ready ([#3090](https://github.com/antvis/X6/issues/3090)) ([019333d](https://github.com/antvis/X6/commit/019333d79d7f22c44c400f29d501497f4323af1a))
|
||||
|
||||
# @antv/x6-sites [1.2.0](https://github.com/antvis/X6/compare/@antv/x6-sites@1.1.2...@antv/x6-sites@1.2.0) (2022-12-16)
|
||||
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
title: Graph
|
||||
order: 0
|
||||
redirect_from:
|
||||
+ /zh/docs
|
||||
+ /zh/docs/api
|
||||
+ /zh/docs/api/graph
|
||||
- /zh/docs
|
||||
- /zh/docs/api
|
||||
- /zh/docs/api/graph
|
||||
---
|
||||
|
||||
## 配置
|
||||
@ -13,29 +13,29 @@ redirect_from:
|
||||
new Graph(options: Options)
|
||||
```
|
||||
|
||||
| 选项 | 类型 | 必选 | 默认值 | 描述 |
|
||||
| ------------------------------------------------------------------------------ | ------------------------------ | :--: | ------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| containers | HTMLElement | ✓ | | 画布的容器。 |
|
||||
| width | number | | - | 画布宽度,默认使用容器宽度。 |
|
||||
| height | number | | - | 画布高度,默认使用容器高度。 |
|
||||
| scaling | { min?: number, max?: number } | | { min: 0.01, max: 16 } | 画布的最小最大缩放级别。 |
|
||||
| [autoResize](/zh/docs/tutorial/basic/graph#画布大小) | boolean \| Element \| Document | | `false` | 是否监听容器大小改变,并自动更新画布大小。 |
|
||||
| [panning](/zh/docs/api/graph/panning) | boolean \| `PanningManager.Options` | | `false` | 画布是否可以拖拽平移,默认禁用。 |
|
||||
| [mousewheel](/zh/docs/api/graph/mousewheel) | boolean \| `MouseWheel.Options` | | `false` | 鼠标滚轮缩放,默认禁用。 |
|
||||
| [grid](/zh/docs/api/graph/grid) | boolean \| number \| `GridManager.Options` | | `false` | 网格,默认使用 `10px` 的网格,但不绘制网格背景。 |
|
||||
| [background](/zh/docs/api/graph/background) | false \| `BackgroundManager.Options` | | `false` | 背景,默认不绘制背景。 |
|
||||
| [translating](/zh/docs/api/interacting/interaction#trasnlating) | `Translating.Options` | | { restrict: false } | 限制节点移动。 |
|
||||
| [embedding](/zh/docs/api/interacting/interaction#embedding) | boolean \| `Embedding.Options` | | `false` | 嵌套节点,默认禁用。 |
|
||||
| [connecting](/zh/docs/api/interacting/interaction#connecting) | `Connecting.Options` | | { snap: false, ... } | 连线选项。 |
|
||||
| [highlighting](/zh/docs/api/interacting/interaction#highlighting) | `Highlighting.Options` | | {...} | 高亮选项。 |
|
||||
| [interacting](/zh/docs/api/interacting/interaction#interacting) | `Interacting.Options` | | { edgeLabelMovable: false } | 定制节点和边的交互行为。 |
|
||||
| [magnetThreshold](/zh/docs/api/graph/view#magnetthreshold) | number \| 'onleave' | | `0` | 鼠标移动多少次后才触发连线,或者设置为 `'onleave'` 时表示鼠标移出元素时才触发连线。 |
|
||||
| [moveThreshold](/zh/docs/api/graph/view#movethreshold) | number | | `0` | 触发 `'mousemove'` 事件之前,允许鼠标移动的次数。 |
|
||||
| [clickThreshold](/zh/docs/api/graph/view#clickthreshold) | number | | `0` | 当鼠标移动次数超过指定的数字时,将不触发鼠标点击事件。 |
|
||||
| [preventDefaultContextMenu](/zh/docs/api/graph/view#preventdefaultcontextmenu) | boolean | | `true` | 是否禁用浏览器默认右键菜单。 |
|
||||
| [preventDefaultBlankAction](/zh/docs/api/graph/view#preventdefaultblankaction) | boolean | | `true` | 在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为。 |
|
||||
| [async](/zh/docs/api/graph/view#async) | boolean | | `true` | 是否异步渲染 |
|
||||
| [virtual](/zh/docs/api/graph/view#virtual) | boolean | | `false` | 是否只渲染可视区域内容 |
|
||||
| [onPortRendered](/zh/docs/api/graph/view#onportrendered) | (args: OnPortRenderedArgs) => void | | - | 当某个连接桩渲染完成时触发的回调。 |
|
||||
| [onEdgeLabelRendered](/zh/docs/api/graph/view#onedgelabelrendered) | (args: OnEdgeLabelRenderedArgs) => void | | - | 当边的文本标签渲染完成时触发的回调。 |
|
||||
| [createCellView](/zh/docs/api/graph/view#createcellview) | (this: Graph, cell: Cell) => CellView \| null \| undefined | | - | 是自定义元素的视图。 |
|
||||
| 选项 | 类型 | 必选 | 描述 | 默认值 |
|
||||
| ------------------------------------------------------------------------------ | ------------------------------ | :--: | ------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| containers | HTMLElement | ✓ | 画布的容器。 | |
|
||||
| width | number | | 画布宽度,默认使用容器宽度。 | - |
|
||||
| height | number | | 画布高度,默认使用容器高度。 | - |
|
||||
| scaling | { min?: number, max?: number } | | 画布的最小最大缩放级别。 | { min: 0.01, max: 16 } |
|
||||
| [autoResize](/zh/docs/tutorial/basic/graph#画布大小) | boolean \| Element \| Document | | 是否监听容器大小改变,并自动更新画布大小。 | `false` |
|
||||
| [panning](/zh/docs/api/graph/panning) | boolean \| `PanningManager.Options` | | 画布是否可以拖拽平移,默认禁用。 | `false` |
|
||||
| [mousewheel](/zh/docs/api/graph/mousewheel) | boolean \| `MouseWheel.Options` | | 鼠标滚轮缩放,默认禁用。 | `false` |
|
||||
| [grid](/zh/docs/api/graph/grid) | boolean \| number \| `GridManager.Options` | | 网格,默认使用 `10px` 的网格,但不绘制网格背景。 | `false` |
|
||||
| [background](/zh/docs/api/graph/background) | false \| `BackgroundManager.Options` | | 背景,默认不绘制背景。 | `false` |
|
||||
| [translating](/zh/docs/api/interacting/interaction#trasnlating) | `Translating.Options` | | 限制节点移动。 | { restrict: false } |
|
||||
| [embedding](/zh/docs/api/interacting/interaction#embedding) | boolean \| `Embedding.Options` | | 嵌套节点,默认禁用。 | `false` |
|
||||
| [connecting](/zh/docs/api/interacting/interaction#connecting) | `Connecting.Options` | | 连线选项。 | { snap: false, ... } |
|
||||
| [highlighting](/zh/docs/api/interacting/interaction#highlighting) | `Highlighting.Options` | | 高亮选项。 | {...} |
|
||||
| [interacting](/zh/docs/api/interacting/interaction#interacting) | `Interacting.Options` | | 定制节点和边的交互行为。 | { edgeLabelMovable: false } |
|
||||
| [magnetThreshold](/zh/docs/api/graph/view#magnetthreshold) | number \| 'onleave' | | 鼠标移动多少次后才触发连线,或者设置为 `'onleave'` 时表示鼠标移出元素时才触发连线。 | `0` |
|
||||
| [moveThreshold](/zh/docs/api/graph/view#movethreshold) | number | | 触发 `'mousemove'` 事件之前,允许鼠标移动的次数。 | `0` |
|
||||
| [clickThreshold](/zh/docs/api/graph/view#clickthreshold) | number | | 当鼠标移动次数超过指定的数字时,将不触发鼠标点击事件。 | `0` |
|
||||
| [preventDefaultContextMenu](/zh/docs/api/graph/view#preventdefaultcontextmenu) | boolean | | 是否禁用浏览器默认右键菜单。 | `true` |
|
||||
| [preventDefaultBlankAction](/zh/docs/api/graph/view#preventdefaultblankaction) | boolean | | 在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为。 | `true` |
|
||||
| [async](/zh/docs/api/graph/view#async) | boolean | | 是否异步渲染 | `true` |
|
||||
| [virtual](/zh/docs/api/graph/view#virtual) | boolean | | 是否只渲染可视区域内容 | `false` |
|
||||
| [onPortRendered](/zh/docs/api/graph/view#onportrendered) | (args: OnPortRenderedArgs) => void | | 当某个连接桩渲染完成时触发的回调。 | - |
|
||||
| [onEdgeLabelRendered](/zh/docs/api/graph/view#onedgelabelrendered) | (args: OnEdgeLabelRenderedArgs) => void | | 当边的文本标签渲染完成时触发的回调。 | - |
|
||||
| [createCellView](/zh/docs/api/graph/view#createcellview) | (this: Graph, cell: Cell) => CellView \| null \| undefined | | 是自定义元素的视图。 | - |
|
||||
|
@ -0,0 +1,842 @@
|
||||
import React from 'react'
|
||||
import { Graph, Node, Path, Edge, Platform } from '@antv/x6'
|
||||
import { Selection } from '@antv/x6-plugin-selection'
|
||||
import { StringExt } from '@antv/x6-common'
|
||||
import classnames from 'classnames'
|
||||
import insertCss from 'insert-css'
|
||||
import { register } from '@antv/x6-react-shape'
|
||||
import { Tooltip, Dropdown } from 'antd'
|
||||
|
||||
// 节点类型
|
||||
enum NodeType {
|
||||
INPUT = 'INPUT', // 数据输入
|
||||
FILTER = 'FILTER', // 数据过滤
|
||||
JOIN = 'JOIN', // 数据连接
|
||||
UNION = 'UNION', // 数据合并
|
||||
AGG = 'AGG', // 数据聚合
|
||||
OUTPUT = 'OUTPUT', // 数据输出
|
||||
}
|
||||
|
||||
// 元素校验状态
|
||||
enum CellStatus {
|
||||
DEFAULT = 'default',
|
||||
SUCCESS = 'success',
|
||||
ERROR = 'error',
|
||||
}
|
||||
|
||||
// 节点位置信息
|
||||
interface Position {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
// 加工类型列表
|
||||
const PROCESSING_TYPE_LIST = [
|
||||
{
|
||||
type: 'FILTER',
|
||||
name: '数据筛选',
|
||||
},
|
||||
{
|
||||
type: 'JOIN',
|
||||
name: '数据连接',
|
||||
},
|
||||
{
|
||||
type: 'UNION',
|
||||
name: '数据合并',
|
||||
},
|
||||
{
|
||||
type: 'AGG',
|
||||
name: '数据聚合',
|
||||
},
|
||||
|
||||
{
|
||||
type: 'OUTPUT',
|
||||
name: '数据输出',
|
||||
},
|
||||
]
|
||||
|
||||
// 不同节点类型的icon
|
||||
const NODE_TYPE_LOGO = {
|
||||
INPUT: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*RXnuTpQ22xkAAAAAAAAAAAAADtOHAQ/original', // 数据输入
|
||||
FILTER: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*ZJ6qToit8P4AAAAAAAAAAAAADtOHAQ/original', // 数据筛选
|
||||
JOIN: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*EHqyQoDeBvIAAAAAAAAAAAAADtOHAQ/original', // 数据连接
|
||||
UNION: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*k4eyRaXv8gsAAAAAAAAAAAAADtOHAQ/original', // 数据合并
|
||||
AGG: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*TKG8R6nfYiAAAAAAAAAAAAAADtOHAQ/original', // 数据聚合
|
||||
OUTPUT: 'https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*zUgORbGg1HIAAAAAAAAAAAAADtOHAQ/original', // 数据输出
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据起点初始下游节点的位置信息
|
||||
* @param node 起始节点
|
||||
* @param graph
|
||||
* @returns
|
||||
*/
|
||||
const getDownstreamNodePosition = (
|
||||
node: Node,
|
||||
graph: Graph,
|
||||
dx = 250,
|
||||
dy = 100,
|
||||
) => {
|
||||
// 找出画布中以该起始节点为起点的相关边的终点id集合
|
||||
const downstreamNodeIdList: string[] = []
|
||||
graph.getEdges().forEach((edge) => {
|
||||
const originEdge = edge.toJSON()?.data
|
||||
if (originEdge.source === node.id) {
|
||||
downstreamNodeIdList.push(originEdge.target)
|
||||
}
|
||||
})
|
||||
// 获取起点的位置信息
|
||||
const position = node.getPosition()
|
||||
let minX = Infinity
|
||||
let maxY = -Infinity
|
||||
graph.getNodes().forEach((graphNode) => {
|
||||
if (downstreamNodeIdList.indexOf(graphNode.id) > -1) {
|
||||
const nodePosition = graphNode.getPosition()
|
||||
// 找到所有节点中最左侧的节点的x坐标
|
||||
if (nodePosition.x < minX) {
|
||||
minX = nodePosition.x
|
||||
}
|
||||
// 找到所有节点中最x下方的节点的y坐标
|
||||
if (nodePosition.y > maxY) {
|
||||
maxY = nodePosition.y
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
x: minX !== Infinity ? minX : position.x + dx,
|
||||
y: maxY !== -Infinity ? maxY + dy : position.y,
|
||||
}
|
||||
}
|
||||
|
||||
// 根据节点的类型获取ports
|
||||
const getPortsByType = (type: NodeType, nodeId: string) => {
|
||||
let ports = []
|
||||
switch (type) {
|
||||
case NodeType.INPUT:
|
||||
ports = [
|
||||
{
|
||||
id: `${nodeId}-out`,
|
||||
group: 'out',
|
||||
},
|
||||
]
|
||||
break
|
||||
case NodeType.OUTPUT:
|
||||
ports = [
|
||||
{
|
||||
id: `${nodeId}-in`,
|
||||
group: 'in',
|
||||
},
|
||||
]
|
||||
break
|
||||
default:
|
||||
ports = [
|
||||
{
|
||||
id: `${nodeId}-in`,
|
||||
group: 'in',
|
||||
},
|
||||
{
|
||||
id: `${nodeId}-out`,
|
||||
group: 'out',
|
||||
},
|
||||
]
|
||||
break
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建节点并添加到画布
|
||||
* @param type 节点类型
|
||||
* @param graph
|
||||
* @param position 节点位置
|
||||
* @returns
|
||||
*/
|
||||
export const createNode = (
|
||||
type: NodeType,
|
||||
graph: Graph,
|
||||
position?: Position,
|
||||
) => {
|
||||
if (!graph) {
|
||||
return {}
|
||||
}
|
||||
let newNode = {}
|
||||
const sameTypeNodes = graph.getNodes().filter(item => item.getData()?.type === type);
|
||||
const typeName = PROCESSING_TYPE_LIST?.find((item) => item.type === type)?.name;
|
||||
const id = StringExt.uuid()
|
||||
const node = {
|
||||
id,
|
||||
shape: 'data-processing-dag-node',
|
||||
x: position?.x,
|
||||
y: position?.y,
|
||||
ports: getPortsByType(type, id),
|
||||
data: {
|
||||
name: `${typeName}_${sameTypeNodes.length + 1}`,
|
||||
type,
|
||||
},
|
||||
}
|
||||
newNode = graph.addNode(node)
|
||||
return newNode
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建边并添加到画布
|
||||
* @param source
|
||||
* @param target
|
||||
* @param graph
|
||||
*/
|
||||
const createEdge = (source: string, target: string, graph: Graph) => {
|
||||
const edge = {
|
||||
id: StringExt.uuid(),
|
||||
shape: 'data-processing-curve',
|
||||
source: {
|
||||
cell: source,
|
||||
port: `${source}-out`,
|
||||
},
|
||||
target: {
|
||||
cell: target,
|
||||
port: `${target}-in`,
|
||||
},
|
||||
zIndex: -1,
|
||||
data: {
|
||||
source,
|
||||
target,
|
||||
},
|
||||
}
|
||||
if (graph) {
|
||||
graph.addEdge(edge)
|
||||
}
|
||||
}
|
||||
|
||||
class DataProcessingDagNode extends React.Component<{
|
||||
node: Node
|
||||
}> {
|
||||
state = {
|
||||
plusActionSelected: false,
|
||||
}
|
||||
|
||||
// 创建下游的节点和边
|
||||
createDownstream = (type: NodeType) => {
|
||||
const { node } = this.props
|
||||
const { graph } = node.model || {}
|
||||
if (graph) {
|
||||
// 获取下游节点的初始位置信息
|
||||
const position = getDownstreamNodePosition(node, graph)
|
||||
// 创建下游节点
|
||||
const newNode = createNode(type, graph, position)
|
||||
const source = node.id
|
||||
const target = newNode.id
|
||||
// 创建该节点出发到下游节点的边
|
||||
createEdge(source, target, graph)
|
||||
}
|
||||
}
|
||||
|
||||
// 点击添加下游+号
|
||||
clickPlusDragMenu = (type: NodeType) => {
|
||||
this.createDownstream(type)
|
||||
this.setState({
|
||||
plusActionSelected: false,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取+号下拉菜单
|
||||
getPlusDagMenu = () => {
|
||||
return (
|
||||
<ul>
|
||||
{
|
||||
PROCESSING_TYPE_LIST.map((item) => {
|
||||
const content = (
|
||||
<a onClick={() => this.clickPlusDragMenu(item.type)}>
|
||||
<i
|
||||
className="node-mini-logo"
|
||||
style={{ backgroundImage: `url(${NODE_TYPE_LOGO[item.type]})` }}
|
||||
/>
|
||||
|
||||
<span>{item.name}</span>
|
||||
</a>
|
||||
)
|
||||
return <li className="each-sub-menu">{content}</li>
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
// 添加下游菜单的打开状态变化
|
||||
onPlusDropdownOpenChange = (value: boolean) => {
|
||||
this.setState({
|
||||
plusActionSelected: value,
|
||||
})
|
||||
}
|
||||
|
||||
// 鼠标进入矩形主区域的时候显示连接桩
|
||||
onMainMouseEnter = () => {
|
||||
const { node } = this.props
|
||||
// 获取该节点下的所有连接桩
|
||||
const ports = node.getPorts() || [];
|
||||
ports.forEach((port) => {
|
||||
node.setPortProp(port.id, 'attrs/circle', { fill: '#fff', stroke: '#85A5FF' })
|
||||
})
|
||||
}
|
||||
|
||||
// 鼠标离开矩形主区域的时候隐藏连接桩
|
||||
onMainMouseLeave = () => {
|
||||
const { node } = this.props
|
||||
// 获取该节点下的所有连接桩
|
||||
const ports = node.getPorts() || []
|
||||
ports.forEach((port) => {
|
||||
node.setPortProp(port.id, 'attrs/circle', { fill: 'transparent', stroke: 'transparent' })
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { plusActionSelected } = this.state
|
||||
const { node } = this.props
|
||||
const data = node?.getData()
|
||||
const { name, type, status, statusMsg } = data
|
||||
|
||||
return (
|
||||
<div className="data-processing-dag-node">
|
||||
<div
|
||||
className="main-area"
|
||||
onMouseEnter={this.onMainMouseEnter}
|
||||
onMouseLeave={this.onMainMouseLeave}
|
||||
>
|
||||
<div className="main-info">
|
||||
{/* 节点类型icon */}
|
||||
<i
|
||||
className="node-logo"
|
||||
style={{ backgroundImage: `url(${NODE_TYPE_LOGO[type]})` }}
|
||||
/>
|
||||
<Tooltip title={name} mouseEnterDelay={0.8}>
|
||||
<div className="ellipsis-row node-name">{name}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{/* 节点状态信息 */}
|
||||
<div className="status-action">
|
||||
{status === CellStatus.ERROR && (
|
||||
<Tooltip title={statusMsg}>
|
||||
<i className="status-icon status-icon-error" />
|
||||
</Tooltip>
|
||||
)}
|
||||
{status === CellStatus.SUCCESS && (
|
||||
<i className="status-icon status-icon-success" />
|
||||
)}
|
||||
|
||||
{/* 节点操作菜单 */}
|
||||
<div className="more-action-container">
|
||||
<i className="more-action" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 添加下游节点 */}
|
||||
{type !== NodeType.OUTPUT && (
|
||||
<div className="plus-dag">
|
||||
<Dropdown
|
||||
dropdownRender={this.getPlusDagMenu}
|
||||
overlayClassName="processing-node-menu"
|
||||
trigger={['click']}
|
||||
placement="bottom"
|
||||
open={plusActionSelected}
|
||||
onOpenChange={this.onPlusDropdownOpenChange}
|
||||
>
|
||||
<i
|
||||
className={classnames('plus-action', {
|
||||
'plus-action-selected': plusActionSelected,
|
||||
})}
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
register({
|
||||
shape: 'data-processing-dag-node',
|
||||
width: 212,
|
||||
height: 48,
|
||||
component: DataProcessingDagNode,
|
||||
// port默认不可见
|
||||
ports: {
|
||||
groups: {
|
||||
in: {
|
||||
position: 'left',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
magnet: true,
|
||||
stroke: 'transparent',
|
||||
strokeWidth: 1,
|
||||
fill: 'transparent',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
out: {
|
||||
position: {
|
||||
name: 'right',
|
||||
args: {
|
||||
dx: -32,
|
||||
},
|
||||
},
|
||||
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
magnet: true,
|
||||
stroke: 'transparent',
|
||||
strokeWidth: 1,
|
||||
fill: 'transparent',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// 注册连线
|
||||
Graph.registerConnector(
|
||||
'curveConnector',
|
||||
(sourcePoint, targetPoint) => {
|
||||
const hgap = Math.abs(targetPoint.x - sourcePoint.x)
|
||||
const path = new Path()
|
||||
path.appendSegment(Path.createSegment('M', sourcePoint.x - 4, sourcePoint.y))
|
||||
path.appendSegment(Path.createSegment('L', sourcePoint.x + 12, sourcePoint.y))
|
||||
// 水平三阶贝塞尔曲线
|
||||
path.appendSegment(
|
||||
Path.createSegment(
|
||||
'C',
|
||||
sourcePoint.x < targetPoint.x ? sourcePoint.x + hgap / 2 : sourcePoint.x - hgap / 2,
|
||||
sourcePoint.y,
|
||||
sourcePoint.x < targetPoint.x ? targetPoint.x - hgap / 2 : targetPoint.x + hgap / 2,
|
||||
targetPoint.y,
|
||||
targetPoint.x - 6,
|
||||
targetPoint.y,
|
||||
),
|
||||
)
|
||||
path.appendSegment(Path.createSegment('L', targetPoint.x + 2, targetPoint.y))
|
||||
|
||||
return path.serialize()
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
Edge.config({
|
||||
markup: [
|
||||
{
|
||||
tagName: 'path',
|
||||
selector: 'wrap',
|
||||
attrs: {
|
||||
fill: 'none',
|
||||
cursor: 'pointer',
|
||||
stroke: 'transparent',
|
||||
strokeLinecap: 'round',
|
||||
},
|
||||
},
|
||||
{
|
||||
tagName: 'path',
|
||||
selector: 'line',
|
||||
attrs: {
|
||||
fill: 'none',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
},
|
||||
],
|
||||
connector: { name: 'curveConnector' },
|
||||
attrs: {
|
||||
wrap: {
|
||||
connection: true,
|
||||
strokeWidth: 10,
|
||||
strokeLinejoin: 'round',
|
||||
},
|
||||
line: {
|
||||
connection: true,
|
||||
stroke: '#A2B1C3',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Graph.registerEdge('data-processing-curve', Edge, true)
|
||||
|
||||
const graph: Graph = new Graph({
|
||||
container: document.getElementById('container')!,
|
||||
panning: {
|
||||
enabled: true,
|
||||
eventTypes: ['leftMouseDown', 'mouseWheel'],
|
||||
},
|
||||
mousewheel: {
|
||||
enabled: true,
|
||||
modifiers: 'ctrl',
|
||||
factor: 1.1,
|
||||
maxScale: 1.5,
|
||||
minScale: 0.5,
|
||||
},
|
||||
highlighting: {
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: '#fff',
|
||||
stroke: '#31d0c6',
|
||||
strokeWidth: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
connecting: {
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
highlight: true,
|
||||
sourceAnchor: {
|
||||
name: 'left',
|
||||
args: {
|
||||
dx: Platform.IS_SAFARI ? 4 : 8,
|
||||
},
|
||||
},
|
||||
targetAnchor: {
|
||||
name: 'right',
|
||||
args: {
|
||||
dx: Platform.IS_SAFARI ? 4 : -8,
|
||||
},
|
||||
},
|
||||
createEdge() {
|
||||
return graph.createEdge({
|
||||
shape: 'data-processing-curve',
|
||||
attrs: {
|
||||
line: {
|
||||
strokeDasharray: '5 5',
|
||||
},
|
||||
},
|
||||
zIndex: -1,
|
||||
})
|
||||
},
|
||||
// 连接桩校验
|
||||
validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
|
||||
// 只能从输出链接桩创建连接
|
||||
if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'in') {
|
||||
return false
|
||||
}
|
||||
// 只能连接到输入链接桩
|
||||
if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'in') {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.use(new Selection({
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberEdge: true,
|
||||
rubberNode: true,
|
||||
modifiers: 'shift',
|
||||
rubberband: true,
|
||||
}))
|
||||
|
||||
// 节点状态列表
|
||||
const nodeStatusList = [
|
||||
{
|
||||
id: 'node-0',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'node-1',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'node-2',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'node-3',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'node-4',
|
||||
status: 'error',
|
||||
statusMsg: '错误信息示例'
|
||||
},
|
||||
]
|
||||
|
||||
// 边状态列表
|
||||
const edgeStatusList = [
|
||||
{
|
||||
id: 'edge-0',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'edge-1',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'edge-2',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
id: 'edge-3',
|
||||
status: 'success',
|
||||
},
|
||||
]
|
||||
|
||||
// 显示节点状态
|
||||
const showNodeStatus = () => {
|
||||
nodeStatusList.forEach((item) => {
|
||||
const { id, status, statusMsg } = item
|
||||
const node = graph.getCellById(id)
|
||||
const data = node.getData() as CellStatus
|
||||
node.setData({
|
||||
...data,
|
||||
status,
|
||||
statusMsg,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 开启边的运行动画
|
||||
const excuteAnimate = () => {
|
||||
graph.getEdges().forEach((edge) => {
|
||||
edge.attr({
|
||||
line: {
|
||||
stroke: '#3471F9',
|
||||
},
|
||||
})
|
||||
edge.attr('line/strokeDasharray', 5)
|
||||
edge.attr('line/style/animation', 'running-line 30s infinite linear')
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭边的动画
|
||||
const stopAnimate = () => {
|
||||
graph.getEdges().forEach((edge) => {
|
||||
edge.attr('line/strokeDasharray', 0)
|
||||
edge.attr('line/style/animation', '')
|
||||
})
|
||||
edgeStatusList.forEach((item) => {
|
||||
const { id, status } = item
|
||||
const edge = graph.getCellById(id)
|
||||
if (status === 'success') {
|
||||
edge.attr('line/stroke', '#52c41a')
|
||||
}
|
||||
if (status === 'error') {
|
||||
edge.attr('line/stroke', '#ff4d4f')
|
||||
}
|
||||
})
|
||||
// 默认选中一个节点
|
||||
graph.select('node-2')
|
||||
}
|
||||
|
||||
fetch('/data/data-processing-dag.json')
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
graph.fromJSON(data)
|
||||
const zoomOptions = {
|
||||
padding: {
|
||||
left: 10,
|
||||
right: 10,
|
||||
},
|
||||
}
|
||||
graph.zoomToFit(zoomOptions)
|
||||
setTimeout(() => {
|
||||
excuteAnimate()
|
||||
}, 2000)
|
||||
setTimeout(() => {
|
||||
showNodeStatus()
|
||||
stopAnimate()
|
||||
}, 3000)
|
||||
})
|
||||
|
||||
|
||||
insertCss(`
|
||||
.data-processing-dag-node {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main-area {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
width: 180px;
|
||||
height: 48px;
|
||||
color: rgba(0, 0, 0, 65%);
|
||||
font-size: 12px;
|
||||
font-family: PingFangSC;
|
||||
line-height: 24px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 -1px 4px 0 rgba(209, 209, 209, 50%), 1px 1px 4px 0 rgba(217, 217, 217, 50%);
|
||||
border-radius: 2px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.main-area:hover {
|
||||
border: 1px solid rgba(0, 0, 0, 10%);
|
||||
box-shadow: 0 -2px 4px 0 rgba(209, 209, 209, 50%), 2px 2px 4px 0 rgba(217, 217, 217, 50%);
|
||||
}
|
||||
|
||||
.node-logo {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.node-name {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
width: 70px;
|
||||
margin-left: 6px;
|
||||
color: rgba(0, 0, 0, 65%);
|
||||
font-size: 12px;
|
||||
font-family: PingFangSC;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.status-action {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.status-icon-error {
|
||||
background: url('https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ')
|
||||
no-repeat center center / 100% 100%;
|
||||
}
|
||||
|
||||
.status-icon-success {
|
||||
background: url('https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ')
|
||||
no-repeat center center / 100% 100%;
|
||||
}
|
||||
|
||||
.more-action-container {
|
||||
margin-left: 12px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.more-action {
|
||||
display: inline-block;
|
||||
width: 3px;
|
||||
height: 15px;
|
||||
background: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*tFw7SIy-ttQAAAAAAAAAAAAADtOHAQ/original')
|
||||
no-repeat center center / 100% 100%;
|
||||
}
|
||||
|
||||
.plus-dag {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
margin-left: 12px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.plus-action {
|
||||
position: absolute;
|
||||
top: calc(50% - 8px);
|
||||
left: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*ScX2R4ODfokAAAAAAAAAAAAADtOHAQ/original')
|
||||
no-repeat center center / 100% 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.plus-action:hover {
|
||||
background-image: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*tRaoS5XhsuQAAAAAAAAAAAAADtOHAQ/original');
|
||||
}
|
||||
|
||||
.plus-action:active,
|
||||
.plus-action-selected {
|
||||
background-image: url('https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*k9cnSaSmlw4AAAAAAAAAAAAADtOHAQ/original');
|
||||
}
|
||||
|
||||
.x6-node-selected .main-area {
|
||||
border-color: #3471f9;
|
||||
}
|
||||
|
||||
.x6-node-selected .plus-dag {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.processing-node-menu {
|
||||
padding: 2px 0;
|
||||
width: 105px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 9px 28px 8px rgba(0, 0, 0, 5%), 0 6px 16px 0 rgba(0, 0, 0, 8%),
|
||||
0 3px 6px -4px rgba(0, 0, 0, 12%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.processing-node-menu ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.processing-node-menu li {
|
||||
list-style:none;
|
||||
}
|
||||
|
||||
.each-sub-menu {
|
||||
padding: 6px 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.each-sub-menu:hover {
|
||||
background-color: rgba(0, 0, 0, 4%);
|
||||
}
|
||||
|
||||
.each-sub-menu a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 16px;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 65%);
|
||||
}
|
||||
|
||||
.each-sub-menu span {
|
||||
margin-left: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.each-disabled-sub-menu a {
|
||||
cursor: not-allowed;
|
||||
color: rgba(0, 0, 0, 35%);
|
||||
}
|
||||
|
||||
.node-mini-logo {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@keyframes running-line {
|
||||
to {
|
||||
stroke-dashoffset: -1000;
|
||||
}
|
||||
}
|
||||
`)
|
@ -16,6 +16,14 @@
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*RPiGRaSus3UAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "dataProcessingDag.tsx",
|
||||
"title": {
|
||||
"zh": "数据加工 DAG 图",
|
||||
"en": "DAG for Data Processing"
|
||||
},
|
||||
"screenshot": "https://mdn.alipayobjects.com/huamei_f4t1bn/afts/img/A*yRLDQ5KgSO4AAAAAAAAAAAAADtOHAQ/original"
|
||||
},
|
||||
{
|
||||
"filename": "er.ts",
|
||||
"title": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@antv/x6-sites",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2",
|
||||
"description": "X6 sites deployed on gh-pages",
|
||||
"scripts": {
|
||||
"dev": "dumi dev",
|
||||
@ -38,6 +38,8 @@
|
||||
"highlight.js": "^10.1.2",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-i18next": "^11.5.0"
|
||||
"react-i18next": "^11.5.0",
|
||||
"classnames": "^2.2.6",
|
||||
"@antv/x6-common": "^2.0.x"
|
||||
}
|
||||
}
|
||||
|
163
sites/x6-sites/public/data/data-processing-dag.json
Normal file
163
sites/x6-sites/public/data/data-processing-dag.json
Normal file
@ -0,0 +1,163 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-0",
|
||||
"shape": "data-processing-dag-node",
|
||||
"x": 0,
|
||||
"y": 100,
|
||||
"ports": [
|
||||
{
|
||||
"id": "node-0-out",
|
||||
"group": "out"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"name": "数据输入_1",
|
||||
"type": "INPUT",
|
||||
"checkStatus": "sucess"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-1",
|
||||
"shape": "data-processing-dag-node",
|
||||
"x": 250,
|
||||
"y": 100,
|
||||
"ports": [
|
||||
{
|
||||
"id": "node-1-in",
|
||||
"group": "in"
|
||||
},
|
||||
{
|
||||
"id": "node-1-out",
|
||||
"group": "out"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"name": "数据筛选_1",
|
||||
"type": "FILTER"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-2",
|
||||
"shape": "data-processing-dag-node",
|
||||
"x": 250,
|
||||
"y": 200,
|
||||
"ports": [
|
||||
{
|
||||
"id": "node-2-out",
|
||||
"group": "out"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"name": "数据输入_2",
|
||||
"type": "INPUT"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-3",
|
||||
"shape": "data-processing-dag-node",
|
||||
"x": 500,
|
||||
"y": 100,
|
||||
"ports": [
|
||||
{
|
||||
"id": "node-3-in",
|
||||
"group": "in"
|
||||
},
|
||||
{
|
||||
"id": "node-3-out",
|
||||
"group": "out"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"name": "数据连接_1",
|
||||
"type": "JOIN"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-4",
|
||||
"shape": "data-processing-dag-node",
|
||||
"x": 750,
|
||||
"y": 100,
|
||||
"ports": [
|
||||
{
|
||||
"id": "node-4-in",
|
||||
"group": "in"
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"name": "数据输出_1",
|
||||
"type": "OUTPUT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-0",
|
||||
"source": {
|
||||
"cell": "node-0",
|
||||
"port": "node-0-out"
|
||||
},
|
||||
"target": {
|
||||
"cell": "node-1",
|
||||
"port": "node-1-in"
|
||||
},
|
||||
"shape": "data-processing-curve",
|
||||
"zIndex": -1,
|
||||
"data": {
|
||||
"source": "node-0",
|
||||
"target": "node-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "edge-1",
|
||||
"source": {
|
||||
"cell": "node-2",
|
||||
"port": "node-2-out"
|
||||
},
|
||||
"target": {
|
||||
"cell": "node-3",
|
||||
"port": "node-3-in"
|
||||
},
|
||||
"shape": "data-processing-curve",
|
||||
"zIndex": -1,
|
||||
"data": {
|
||||
"source": "node-2",
|
||||
"target": "node-3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "edge-2",
|
||||
"source": {
|
||||
"cell": "node-1",
|
||||
"port": "node-1-out"
|
||||
},
|
||||
"target": {
|
||||
"cell": "node-3",
|
||||
"port": "node-3-in"
|
||||
},
|
||||
"shape": "data-processing-curve",
|
||||
"zIndex": -1,
|
||||
"data": {
|
||||
"source": "node-1",
|
||||
"target": "node-3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "edge-3",
|
||||
"source": {
|
||||
"cell": "node-3",
|
||||
"port": "node-3-out"
|
||||
},
|
||||
"target": {
|
||||
"cell": "node-4",
|
||||
"port": "node-4-in"
|
||||
},
|
||||
"shape": "data-processing-curve",
|
||||
"zIndex": -1,
|
||||
"data": {
|
||||
"source": "node-3",
|
||||
"target": "node-4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user