Skip to content

Commit 9e3dd49

Browse files
committed
feat: 1.1.19工作流新的拖拽模式
1 parent 2d65cc3 commit 9e3dd49

File tree

112 files changed

+96659
-50869
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+96659
-50869
lines changed

web/package-lock.json

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

web/packages/apiServices/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@dataspherestudio/apiServices",
3-
"version": "1.1.18",
3+
"version": "1.1.19",
44
"dependencies": {
5-
"@dataspherestudio/shared": "^1.1.18"
5+
"@dataspherestudio/shared": "^1.1.19"
66
}
77
}

web/packages/cyeditor/README.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# 说明
2+
Cytoscape.js 是一个用于分析和可视化复杂网络数据的 JavaScript 库。它主要用于渲染图形,支持节点和边的自定义样式,并提供了丰富的交互功能。Cytoscape.js 可以用于创建网络图(如社交网络、生物学网络等)、流程图、组织图、文件系统图等。
3+
主要特点:
4+
5+
高度可定制:节点和边的样式可以自定义,支持多种形状、颜色、大小等属性。
6+
强大的布局算法:内置多种布局算法,如环形布局、力导布局、矩阵布局等,也支持自定义布局。
7+
丰富的交互:支持多种交互方式,如拖拽、缩放、选择、悬停等,可以方便地与其他库集成。
8+
插件扩展:通过插件,可以扩展 Cytoscape.js 的功能,如添加新的布局算法、新的交互方式等。
9+
数据驱动:Cytoscape.js 使用 JSON 格式来表示网络数据,方便数据处理和管理。
10+
11+
cyeditor 使用Cytoscape.js配合一些扩展开发实现DSS工作流编辑视图功能。
12+
13+
# 目录及文件说明
14+
15+
```
16+
├─cyeditor-context-menu # 右键菜单扩展
17+
├─cyeditor-dom-node # DOM节点
18+
├─cyeditor-drag-add-nodes # 节点拖拽添加
19+
├─cyeditor-edgehandles # 连线
20+
│ └─edgehandles
21+
├─cyeditor-navigator # 缩略图导航
22+
├─cyeditor-snap-grid # 网格画布
23+
├─defaults # 默认设置
24+
├─utils
25+
├─index.css
26+
└─index.js
27+
```
28+
29+
# 开发调试
30+
31+
next-web目录下启动
32+
33+
```
34+
# 调试
35+
npm run serve_cyeditor
36+
# 构建
37+
npm run build_cyeditor
38+
```
39+
40+
# 配置项
41+
42+
```json
43+
{
44+
cy: { // cytoscape.js的配置
45+
layout: {}, // 布局方式
46+
styleEnabled: true,
47+
style: [], // cytoscape.js的节点、连线样式配置
48+
minZoom: 0.1,
49+
maxZoom: 10
50+
},
51+
editor: { // 编辑器的配置
52+
container: '', // 组件初始化dom
53+
zoomRate: 0.2,
54+
lineType: 'bezier',
55+
dragAddNodes: true,
56+
snapGrid: true,
57+
contextMenu: true,
58+
navigator: true,
59+
nodeTypes: [], // 节点类型
60+
beforeAdd (el) {
61+
return true
62+
},
63+
afterAdd (el) {
64+
65+
}
66+
}
67+
}
68+
```
69+
# API
70+
- deleteSelected
71+
72+
设置viewport进行缩放
73+
74+
- save
75+
76+
设置viewport进行缩放
77+
78+
- fit
79+
80+
设置画布viewport缩放显示所有元素
81+
- zoom
82+
83+
设置viewport进行缩放
84+
85+
- toggleGrid
86+
87+
切换网格辅助
88+
89+
- jpg
90+
- png
91+
- json
92+
93+
JSON格式数据设置、获取
94+
95+
- data
96+
97+
设置、获取关联的自定义数据
98+
99+
- removeData
100+
101+
删除关联的自定义数据
102+
- destroy
103+
104+
# 使用
105+
106+
```javascript
107+
const cyeditorel = ref<any>(null);
108+
onMounted(() => {
109+
const container = cyeditorel.value;
110+
let config = {
111+
cy: {
112+
layout: {
113+
name: 'klay',
114+
rows: 5,
115+
},
116+
styleEnabled: true,
117+
minZoom: 0.1,
118+
maxZoom: 10,
119+
},
120+
editor: {
121+
container,
122+
zoomRate: 0.2,
123+
lineType: 'bezier',
124+
dragAddNodes: true,
125+
snapGrid: true,
126+
contextMenu: true,
127+
navigator: true,
128+
// nodeTypes: [],
129+
beforeAdd() {
130+
return true;
131+
},
132+
afterAdd() {
133+
//
134+
},
135+
},
136+
};
137+
const { editor, cy } = new CyEditor(config);
138+
editor.json({
139+
boxSelectionEnabled: true,
140+
elements: props.data,
141+
pan: { x: 0, y: 0 },
142+
panningEnabled: true,
143+
userPanningEnabled: true,
144+
userZoomingEnabled: true,
145+
zoom: 1,
146+
zoomingEnabled: true,
147+
});
148+
cy.layout(config.cy.layout).run();
149+
editor.on('change', (scope, editor) => {
150+
let json = editor.json();
151+
console.log(json);
152+
});
153+
});
154+
```
155+
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import utils from '../utils'
2+
3+
const defaults = {
4+
menus: [
5+
{
6+
id: 'remove',
7+
content: 'remove',
8+
disabled: false,
9+
divider: true
10+
},
11+
{
12+
id: 'hide',
13+
content: 'hide',
14+
disabled: false
15+
}
16+
],
17+
beforeShow: (e) => { return e.target.isNode() || e.target.isEdge() },
18+
beforeClose: () => { return true }
19+
}
20+
21+
class ContextMenu {
22+
constructor(cy, params) {
23+
this.cy = cy
24+
this._options = Object.assign({}, defaults, params)
25+
this._listeners = {}
26+
this._init()
27+
}
28+
_init() {
29+
this._initContainer()
30+
this._initDom()
31+
this._initEvents()
32+
}
33+
34+
_initContainer() {
35+
this._container = this.cy.container()
36+
this.ctxmenu = document.createElement('div')
37+
this.ctxmenu.className = 'cy-editor-ctx-menu'
38+
this._container.append(this.ctxmenu)
39+
}
40+
41+
_initDom() {
42+
function getSvgIcon(icon) {
43+
return `<svg aria-hidden="true" class="icon designer-menu-li-icon"><use xlink:href="#icon-${icon}"></use></svg>`
44+
}
45+
this.ctxmenu.innerHTML = this._options.menus.reduce((str, item) => {
46+
return str + `<div class="ctx-menu-item ${item.disabled ? 'ctx-menu-item-disabled' : ''}" data-menu-item="${item.id}">
47+
${getSvgIcon(item.icon)}
48+
<span class="ctx-menu-item-title">${item.content}</span>
49+
${item.children && item.children.length ? '>' : ''}
50+
${ item.children && item.children.length ?
51+
`<div class="ctx-submenu-wrap">
52+
${item.children.reduce((text, child) => text + `<div class="ctx-submenu-item" data-menu-item="${item.id}" data-submenu-item="${child.value}">${getSvgIcon(child.icon)}<span>${child.text}</span></div>`, '')}
53+
</div>` :
54+
''
55+
}
56+
</div>`;
57+
}, '');
58+
}
59+
60+
_initEvents() {
61+
this._listeners.eventCyTap = (event) => {
62+
this.renderedPos = event.renderedPosition || event.cyRenderedPosition
63+
let left = this.renderedPos.x
64+
let top = this.renderedPos.y
65+
utils.css(this.ctxmenu, {
66+
top: top + 'px',
67+
left: (left + 200) + 'px'
68+
})
69+
this.show(event)
70+
}
71+
this._listeners.eventTapstart = (e) => {
72+
this.close(e)
73+
}
74+
this._listeners.click = (e) => {
75+
e.stopPropagation();
76+
let target = e.target;
77+
let id = target.getAttribute('data-menu-item');
78+
if (!id) {
79+
target = e.target.parentNode;
80+
id = target.getAttribute('data-menu-item');
81+
}
82+
let menuItem = this._options.menus.find(item => item.id === id);
83+
const subId = target.getAttribute('data-submenu-item');
84+
if (subId) {
85+
menuItem = menuItem.children.find(item => item.value === subId);
86+
menuItem.id = subId;
87+
}
88+
const pan = this.triggerEvt.cy.pan()
89+
const zoom = this.triggerEvt.cy.zoom()
90+
this.cy.trigger('cyeditor.ctxmenu', {
91+
menuItem,
92+
target: this.triggerEvt.target,
93+
event: {
94+
offsetX: (this.renderedPos.x - pan.x) / zoom,//+ 75 ,
95+
offsetY: (this.renderedPos.y - pan.y) / zoom //+ 20s
96+
}
97+
})
98+
this.close(e);
99+
}
100+
this.ctxmenu.addEventListener('mousedown', this._listeners.click)
101+
this.cy.on('cxttap', this._listeners.eventCyTap)
102+
this.cy.on('tapstart', this._listeners.eventTapstart)
103+
}
104+
105+
disable(id, disabled = true) {
106+
const items = utils.query(`.cy-editor-ctx-menu [data-menu-item=${id}]`)
107+
items.forEach(menuItem => {
108+
if (disabled) {
109+
utils.addClass(menuItem, 'ctx-menu-item-disabled')
110+
} else {
111+
utils.removeClass(menuItem, 'ctx-menu-item-disabled')
112+
}
113+
})
114+
}
115+
116+
changeMenus(menus) {
117+
this._options.menus = menus
118+
this._initDom()
119+
}
120+
121+
show(e) {
122+
if (e.target.data().type === 'edgehandle') return
123+
this.triggerEvt = e;
124+
if (typeof this._options.beforeShow === 'function' && !this.isShow) {
125+
const show = this._options.beforeShow(e, this._options.menus.slice(0))
126+
if (!show) return
127+
if (show && show.then) {
128+
show.then((res) => {
129+
if (res) {
130+
utils.css(this.ctxmenu, {
131+
display: 'block'
132+
})
133+
this.isShow = true
134+
}
135+
})
136+
return
137+
}
138+
if (Array.isArray(show) && show.length) {
139+
this.changeMenus(show)
140+
} else {
141+
return
142+
}
143+
utils.css(this.ctxmenu, {
144+
display: 'block'
145+
})
146+
this.isShow = true
147+
}
148+
}
149+
150+
close(e) {
151+
if (typeof this._options.beforeShow === 'function' && this.isShow) {
152+
const close = this._options.beforeClose(e)
153+
if (close === true) {
154+
utils.css(this.ctxmenu, {
155+
display: 'none'
156+
})
157+
this.isShow = false
158+
} else if (close.then) {
159+
close.then(() => {
160+
utils.css(this.ctxmenu, {
161+
display: 'none'
162+
})
163+
this.isShow = false
164+
})
165+
}
166+
}
167+
}
168+
169+
destroy() {
170+
this.ctxmenu.removeEventListener('mousedown', this._listeners.click)
171+
this.cy.off('tapstart', this._listeners.eventTapstart)
172+
this.cy.off('cxttap', this._listeners.eventCyTap)
173+
}
174+
}
175+
176+
export default (cytoscape) => {
177+
if (!cytoscape) {
178+
return
179+
}
180+
181+
cytoscape('core', 'contextMenu', function (options) {
182+
return new ContextMenu(this, options)
183+
})
184+
}

0 commit comments

Comments
 (0)