mirror of
https://gitee.com/antv/g6.git
synced 2024-11-30 10:48:24 +08:00
fix: remove custom group code
This commit is contained in:
parent
1a7ef1d119
commit
4fd48827df
@ -1,241 +0,0 @@
|
|||||||
---
|
|
||||||
title: Node Group
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
> The title of Node Group is supported from G6 V3.1.2.
|
|
||||||
|
|
||||||
Node Group is a practical function for graph visualization. It is supported from G6 V3.0.5. Refer to the demo <a href='/en/examples/interaction/nodeGroup' target='_blank'>Demo</a>. <br /><img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*G1OBSJf672QAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
||||||
|
|
||||||
### Data Structure
|
|
||||||
|
|
||||||
In data, Node Group are defined as array `groups`, and each node data has a property `groupId`.
|
|
||||||
|
|
||||||
The `title` for a group can be a string or an object:
|
|
||||||
|
|
||||||
- When the `title` is a string, it indicates the text of the group title. The styles and the position are fixed;
|
|
||||||
- When the `title` is an object, users are able to define the styles and position for the group title. The object contains:
|
|
||||||
- text: required, a string indicates the text of the group title;
|
|
||||||
- offsetX: the x offset of the title, `0` by default;
|
|
||||||
- offsetY: the y offset of the title, `0` by default;
|
|
||||||
- stroke: the stroke color. The `fill`, `fontSize`, and other [Label Styles on Node](/en/docs/manual/middle/elements/nodes/defaultNode/#label-and-labelcfg).
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: 'The 1st group',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: 0,
|
|
||||||
offsetY: 0
|
|
||||||
},
|
|
||||||
parentId: 'p1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
parentId: 'p1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Render the Node Group
|
|
||||||
|
|
||||||
If there are `groupId` in node data, G6 will render the group for the node automatically. You need to defined the `x` and `y` for nodes when there is no layout method for the graph.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node6',
|
|
||||||
groupId: 'group3',
|
|
||||||
label: 'rect',
|
|
||||||
x: 100,
|
|
||||||
y: 300,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'fck',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node9',
|
|
||||||
label: 'noGroup1',
|
|
||||||
groupId: 'p1',
|
|
||||||
x: 300,
|
|
||||||
y: 210,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node7',
|
|
||||||
groupId: 'p1',
|
|
||||||
label: 'node7-p1',
|
|
||||||
x: 200,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node10',
|
|
||||||
label: 'noGroup',
|
|
||||||
groupId: 'p2',
|
|
||||||
x: 300,
|
|
||||||
y: 210,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node2',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: 'The first group',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: -30,
|
|
||||||
offsetY: 30,
|
|
||||||
},
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group3',
|
|
||||||
parentId: 'p2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'mountNode',
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
modes: {
|
|
||||||
default: ['drag-canvas'],
|
|
||||||
},
|
|
||||||
defaultNode: {
|
|
||||||
type: 'circle',
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#bae7ff',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
||||||
```
|
|
||||||
|
|
||||||
The result: <br /><img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*iftmRrdqR7cAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
||||||
|
|
||||||
<br />To controll the nodes and the groups, we now assign the behaviors to them.
|
|
||||||
|
|
||||||
### Manipulate the Group
|
|
||||||
|
|
||||||
The built-in [Behavior](/en/docs/manual/middle/states/defaultBehavior)s `drag-group`, `collapse-expand-group`, and `drag-node-with-group` allow user to manipulate the group:
|
|
||||||
|
|
||||||
- Drag the group;
|
|
||||||
- Unrelate the node and its group by dragging the node out of the group;
|
|
||||||
- Double click to expand/collapse the group:
|
|
||||||
- When the group is collapsed, the edges linked to the inner nodes will link to the group;
|
|
||||||
- When the group is expanded, the related edges are restored.
|
|
||||||
- When user is dragging a node, the node's group will be highlighted; when the node is dragged to another group, the corresponding group will be highlighted
|
|
||||||
- **Do not Support** ~~Dropping a node into another group~~.
|
|
||||||
|
|
||||||
#### drag-group
|
|
||||||
|
|
||||||
`drag-group` is a Behavior which supports the group dragging.
|
|
||||||
|
|
||||||
#### collapse-expand-group
|
|
||||||
|
|
||||||
`collapse-expand-group` is a Behavior which supports expand and collapse the group by double click.
|
|
||||||
|
|
||||||
Now, we only support collapse and expand the group by double click.
|
|
||||||
|
|
||||||
#### drag-node-with-group
|
|
||||||
|
|
||||||
`drag-node-with-group` is a Behavior that similar to `drag-node`. But it is applied on the node which has a group. The group of the node will be changed by dragging.
|
|
||||||
|
|
||||||
We do not support dragging multiple nodes in/out a group.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'mountNode',
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
modes: {
|
|
||||||
default: ['drag-group', 'collapse-expand-group', 'drag-node-with-group'],
|
|
||||||
},
|
|
||||||
defaultNode: {
|
|
||||||
type: 'circleNode',
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#bae7ff',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Assigning the three built-in Behavior into `modes` of the graph instance results in:
|
|
||||||
|
|
||||||
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*VsMbRqOJe2sAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
@ -1,245 +0,0 @@
|
|||||||
---
|
|
||||||
title: 节点分组 Group
|
|
||||||
order: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
> New Feature:自 G6 3.1.2 开始支持自定义节点分组的标题了,可以渲染带有标题的分组。
|
|
||||||
|
|
||||||
对于熟悉图可视化类库的用户来说,节点分组可能是比较实用的一个功能。自 G6 3.0.5 版本开始,G6 加入了节点分组的功能,详情参考 <a href='/zh/examples/interaction/nodeGroup' target='_blank'>Demo</a>。<br /><img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*G1OBSJf672QAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
||||||
|
|
||||||
### 数据结构
|
|
||||||
|
|
||||||
新增节点分组功能时,尽量保持了 G6 数据结构的稳定性。为了体现分组的特性,我们在 nodes 数据项中加入了 groupId 属性,另外新增了 `groups` 字段,用于表示数据中所包括的分组及各分组之间的层级关系。
|
|
||||||
|
|
||||||
当 groups 中的对象包括 title 属性字段时,表示要渲染带有标题的分组,title 字段的类型可以是 string 或 object:
|
|
||||||
|
|
||||||
- title:类型为 string 时,值表示标题名称,不能设置任何样式,也不能调整标题位置;
|
|
||||||
- title 为 object 时,可以设置标题的样式及位置,title 中各字段含义:
|
|
||||||
- text:必选,分组的标题,类型为 string;
|
|
||||||
- offsetX:可选,默认为 0,表示 x 方向上的偏移量;
|
|
||||||
- offsetY:可选,默认为 0,表示 y 方向上的偏移量;
|
|
||||||
- stroke:字体边框颜色,同时也支持 fill、fontSize 等所有的 [节点上的文本样式属性](/zh/docs/manual/middle/elements/nodes/defaultNode/#标签文本-label-及其配置-labelcfg)。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 100
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: '第一个分组',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: 0,
|
|
||||||
offsetY: 0
|
|
||||||
},
|
|
||||||
parentId: 'p1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
parentId: 'p1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p1'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 如何渲染 group
|
|
||||||
|
|
||||||
当 nodes 中存在 `groupId` 属性字段时,在渲染过程中,G6 会自动渲染分组。当存在 groups 属性时,G6 会自动判断各分组之间的层级关系,并渲染出嵌套的分组。但当没有使用任何布局的时候,需要在 nodes 中指定各个节点的坐标信息,即节点的 `x` 和 `y` 属性值。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node6',
|
|
||||||
groupId: 'group3',
|
|
||||||
label: 'rect',
|
|
||||||
x: 100,
|
|
||||||
y: 300,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'fck',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node9',
|
|
||||||
label: 'noGroup1',
|
|
||||||
groupId: 'p1',
|
|
||||||
x: 300,
|
|
||||||
y: 210,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node7',
|
|
||||||
groupId: 'p1',
|
|
||||||
label: 'node7-p1',
|
|
||||||
x: 200,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node10',
|
|
||||||
label: 'noGroup',
|
|
||||||
groupId: 'p2',
|
|
||||||
x: 300,
|
|
||||||
y: 210,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node2',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: '第一个分组',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: -30,
|
|
||||||
offsetY: 30,
|
|
||||||
},
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group3',
|
|
||||||
parentId: 'p2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'mountNode',
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
modes: {
|
|
||||||
default: ['drag-canvas'],
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#bae7ff',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
||||||
```
|
|
||||||
|
|
||||||
渲染的效果如下图所示:<br /><img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*iftmRrdqR7cAAAAAAAAAAABkARQnAQ' width=400 alt='img'/><br />此时,不能对分组中的节点及分组进行任何操作,接下来,我们介绍可以对分组进行的各种操作。
|
|
||||||
|
|
||||||
### 操作分组
|
|
||||||
|
|
||||||
只是简单地将分组渲染出来,并没有多大的实用价值,只有支持一系列的交互操作后,才能最大程度地体现分组的价值。
|
|
||||||
|
|
||||||
在 G6 中,我们内置了 `drag-group`、`collapse-expand-group` 及 `drag-node-with-group` 三个 [Behavior](/zh/docs/manual/middle/states/defaultBehavior),共支持以下的交互行为:
|
|
||||||
|
|
||||||
- 拖动分组;
|
|
||||||
- 通过拖拽,动态改变分组中的节点数量及分组大小;
|
|
||||||
- 将一个分组从父分组中拖拽出来,并取消分组直接的关联关系,动态改变父分组的大小;
|
|
||||||
- 双击分组,收起和展开分组:
|
|
||||||
- 当收起分组后,与分组节点中的连线会自动连到分组上;
|
|
||||||
- 展开分组后,恢复之前的连接和位置。
|
|
||||||
- 拖动节点,所在的分组高亮,当拖到其他分组时,其他分组高亮;
|
|
||||||
- [暂不支持] ~~将分组拖入到另外个分组,并改变分组层级的所属关系~~。
|
|
||||||
|
|
||||||
#### drag-group
|
|
||||||
|
|
||||||
`drag-group` Behavior,支持拖动分组,拖动分组过程中,会动态改变分组中节点和边的位置,在拖拽完成以后,保持分组和节点的相对位置不变。
|
|
||||||
|
|
||||||
#### collapse-expand-group
|
|
||||||
|
|
||||||
`collapse-expand-group` Behavior,支持双击分组收起和展开分组,收起分组以后,隐藏分组中的所有节点,外部节点和分组中节点有连线的情况下,所有连接会连接到分组上面。
|
|
||||||
|
|
||||||
优化目前只支持双击交互,正式发布时,会支持用户自定义交互方式,来实现分组的收起和展开。
|
|
||||||
|
|
||||||
#### drag-node-with-group
|
|
||||||
|
|
||||||
`drag-node-with-group` Behavior 和 `drag-node` 类似,但该 Behavior 仅用于用 group 时 node 的拖拽。拖拽 node 过程中,会动态改变 node 所在的分组。
|
|
||||||
|
|
||||||
优化目前暂不支持将多个节点拖出拖入到分组中。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'mountNode',
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
modes: {
|
|
||||||
default: ['drag-group', 'collapse-expand-group', 'drag-node-with-group'],
|
|
||||||
},
|
|
||||||
defaultNode: {
|
|
||||||
type: 'circleNode',
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#bae7ff',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
将这三个内置提供的 Behavior 加入到 `modes` 中以后的效果如下图所示。
|
|
||||||
|
|
||||||
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*VsMbRqOJe2sAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
||||||
|
|
||||||
### 适用场景
|
|
||||||
|
|
||||||
1. 风控、反洗钱、保险骗保、网络诈骗、信用卡诈骗等场景下团伙分析;
|
|
||||||
2. 特征分析:同一个分组中的节点在某些特征上面比较相似;
|
|
||||||
3. 整理节点:当类似的节点放到一个分组中,只渲染分组,不渲染节点,减少干扰元素。
|
|
@ -3,7 +3,7 @@ title: The Visual Level of Node and Edge
|
|||||||
order: 4
|
order: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
The visual levels (zIndex) of nodes and edges are refered to their [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group) (hereinafter referred to as Shape). (<span style="background-color: rgb(251, 233, 231); color: rgb(139, 53, 56)"><strong>⚠️Attention:</strong></span> The Graphics Group is different from the [Node Group](/en/docs/manual/middle/discard/nodeGroup), the differences are described in [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group)).
|
The visual levels (zIndex) of nodes and edges are refered to their [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group) (hereinafter referred to as Shape). (<span style="background-color: rgb(251, 233, 231); color: rgb(139, 53, 56)"><strong>⚠️Attention:</strong></span> The Graphics Group is different from the [Node Combo](/en/docs/manual/middle/discard/nodeGroup), the differences are described in [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group)).
|
||||||
|
|
||||||
In [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group), we stated: All the nodes instances in a Graph is grouped by a Group named `nodeGroup`, all the edges instances are grouped by `edgeGroup`. And the visual level (zIndex) of `nodeGroup` is higher than `edgeGroup`, which means all the nodes will be drawed on the top of all the edges.
|
In [Graphics Group](/en/docs/manual/middle/elements/shape/graphics-group), we stated: All the nodes instances in a Graph is grouped by a Group named `nodeGroup`, all the edges instances are grouped by `edgeGroup`. And the visual level (zIndex) of `nodeGroup` is higher than `edgeGroup`, which means all the nodes will be drawed on the top of all the edges.
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ title: 节点与边的层级
|
|||||||
order: 4
|
order: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
节点与边在视觉上的层级涉及到了它们相对应的 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group)。本文提到的所有分组 Group 都为 G6 的图形分组 Group,而非 G6 的 [节点分组 Group](/zh/docs/manual/middle/discard/nodeGroup),请注意区分这两种 Group,其区别在 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group) 中说明。
|
节点与边在视觉上的层级涉及到了它们相对应的 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group)。本文提到的所有分组 Group 都为 G6 的图形分组 Group,而非 G6 的 [节点分组 Combo](/zh/docs/manual/middle/discard/nodeGroup),其区别在 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group) 中说明。
|
||||||
|
|
||||||
在 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group) 中我们提到:在 G6 中,Graph 的一个实例中的所有节点属于同一个变量名为 `nodeGroup` 的 group,所有的边属于同一个变量名为 `edgeGroup` 的 group。节点 group 在视觉上的层级(zIndex)高于边 group,即所有节点会绘制在所有边的上层。
|
在 [图形分组 Group](/zh/docs/manual/middle/elements/shape/graphics-group) 中我们提到:在 G6 中,Graph 的一个实例中的所有节点属于同一个变量名为 `nodeGroup` 的 group,所有的边属于同一个变量名为 `edgeGroup` 的 group。节点 group 在视觉上的层级(zIndex)高于边 group,即所有节点会绘制在所有边的上层。
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@ title: 图形分组 Group
|
|||||||
order: 2
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
<span style="background-color: rgb(251, 233, 231); color: rgb(139, 53, 56)"> <strong>⚠️ 注意:</strong></span> <br /> 图形分组 Group 与 [节点分组 Group](/zh/docs/manual/middle/discard/nodeGroup) 虽然都名为 Group,但属于不同层次的概念。
|
<span style="background-color: rgb(251, 233, 231); color: rgb(139, 53, 56)"> <strong>⚠️ 注意:</strong></span> <br /> 图形分组 Group 与 [节点分组 Combo](/zh/docs/manual/middle/discard/nodeGroup) 属于不同层次的概念。
|
||||||
|
|
||||||
- 图形分组针对 [图形 Shape](/zh/docs/manual/middle/elements/shape/shape-keyshape) 层次的分组;
|
- 图形分组针对 [图形 Shape](/zh/docs/manual/middle/elements/shape/shape-keyshape) 层次的分组;
|
||||||
- [节点分组 Group](/zh/docs/manual/middle/discard/nodeGroup) 是针对 [节点](/zh/docs/manual/middle/elements/nodes/defaultNode) 的分组,与数据结构中的层次、分组对应。
|
- [节点分组 Combo](/zh/docs/manual/middle/discard/nodeGroup) 是针对 [节点](/zh/docs/manual/middle/elements/nodes/defaultNode) 的分组,与数据结构中的层次、分组对应。
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
@ -590,77 +590,6 @@ graph.on('itemcollapsed', (e) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### collapse-expand-group
|
|
||||||
|
|
||||||
- 含义:收起和展开群组;
|
|
||||||
- 配置项:
|
|
||||||
- `type:'collapse-expand-group'`
|
|
||||||
- `trigger`:收起和展开节点分组的方式。支持 `'click'` 和 `'dblclick'` 两种方式。默认为 `'dblclick'`,即双击。
|
|
||||||
|
|
||||||
**使用默认配置**
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
modes: {
|
|
||||||
default: ['collapse-expand-group'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**使用自定义参数**<br />配置 `trigger` 参数为 **`click`** 后,单击节点分组即可收起或展开分组。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
modes: {
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
type: 'collapse-expand-group',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*znCaS48_BpgAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
|
||||||
|
|
||||||
### drag-group
|
|
||||||
|
|
||||||
- 含义:拖动节点分组;
|
|
||||||
- 配置项:
|
|
||||||
- `type: 'drag-group'`;
|
|
||||||
- `delegateStyle`:拖动节点分组时 `delegate` 的样式。
|
|
||||||
|
|
||||||
**使用默认配置**
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
modes: {
|
|
||||||
default: ['drag-group'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### drag-node-with-group
|
|
||||||
|
|
||||||
- 含义:拖动节点分组中的节点;
|
|
||||||
- 配置项:
|
|
||||||
- `type:'drag-node-with-group'`;
|
|
||||||
- `delegateStyle`:拖动节点时 `delegate` 的样式;
|
|
||||||
- `maxMultiple`;
|
|
||||||
- `minMultiple`;
|
|
||||||
- `shouldBegin(e)`:是否允许当前被操作的节点被拖拽。
|
|
||||||
|
|
||||||
**使用默认配置**
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
modes: {
|
|
||||||
default: ['drag-node-with-group'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### create-edge
|
### create-edge
|
||||||
|
|
||||||
- 含义:通过交互创建边;
|
- 含义:通过交互创建边;
|
||||||
|
@ -229,17 +229,17 @@ graph.on('edge:click', (e) => {
|
|||||||
node.style.fill = 'steelblue';
|
node.style.fill = 'steelblue';
|
||||||
switch (node.class) {
|
switch (node.class) {
|
||||||
case 'c0': {
|
case 'c0': {
|
||||||
node.shape = 'circle';
|
node.type = 'circle';
|
||||||
node.size = 30;
|
node.size = 30;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c1': {
|
case 'c1': {
|
||||||
node.shape = 'rect';
|
node.type = 'rect';
|
||||||
node.size = [35, 20];
|
node.size = [35, 20];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c2': {
|
case 'c2': {
|
||||||
node.shape = 'ellipse';
|
node.type = 'ellipse';
|
||||||
node.size = [35, 20];
|
node.size = [35, 20];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -231,17 +231,17 @@ graph.on('edge:click', (e) => {
|
|||||||
node.style.fill = 'steelblue';
|
node.style.fill = 'steelblue';
|
||||||
switch (node.class) {
|
switch (node.class) {
|
||||||
case 'c0': {
|
case 'c0': {
|
||||||
node.shape = 'circle';
|
node.type = 'circle';
|
||||||
node.size = 30;
|
node.size = 30;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c1': {
|
case 'c1': {
|
||||||
node.shape = 'rect';
|
node.type = 'rect';
|
||||||
node.size = [35, 20];
|
node.size = [35, 20];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c2': {
|
case 'c2': {
|
||||||
node.shape = 'ellipse';
|
node.type = 'ellipse';
|
||||||
node.size = [35, 20];
|
node.size = [35, 20];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ const loadData = (data) => {
|
|||||||
mapNodeSizeAndFontSize(showNodes, 'count', [40, 120]);
|
mapNodeSizeAndFontSize(showNodes, 'count', [40, 120]);
|
||||||
showNodes.forEach((snode) => {
|
showNodes.forEach((snode) => {
|
||||||
if (snode.size < 80) {
|
if (snode.size < 80) {
|
||||||
snode.shape = 'circle';
|
snode.type = 'circle';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -584,7 +584,7 @@ graph.on('node:click', (e) => {
|
|||||||
node.style.lineWidth = 0;
|
node.style.lineWidth = 0;
|
||||||
node.style.opacity = 1;
|
node.style.opacity = 1;
|
||||||
if (node.neighbor) {
|
if (node.neighbor) {
|
||||||
node.shape = 'animate-circle';
|
node.type = 'animate-circle';
|
||||||
node.label = node.text;
|
node.label = node.text;
|
||||||
const color = model.style.fill;
|
const color = model.style.fill;
|
||||||
node.color = color;
|
node.color = color;
|
||||||
|
@ -760,7 +760,7 @@ graph.on('node:click', (e) => {
|
|||||||
node.style.lineWidth = 0;
|
node.style.lineWidth = 0;
|
||||||
node.style.opacity = 1;
|
node.style.opacity = 1;
|
||||||
if (node.isLeaf) {
|
if (node.isLeaf) {
|
||||||
node.shape = 'animate-circle';
|
node.type = 'animate-circle';
|
||||||
let color = 'l(0)';
|
let color = 'l(0)';
|
||||||
const parentsNum = parents.length;
|
const parentsNum = parents.length;
|
||||||
parents.forEach((parent, i) => {
|
parents.forEach((parent, i) => {
|
||||||
@ -784,7 +784,7 @@ graph.on('node:click', (e) => {
|
|||||||
position: 'center',
|
position: 'center',
|
||||||
};
|
};
|
||||||
} else if (node.level !== 0) {
|
} else if (node.level !== 0) {
|
||||||
node.shape = 'circle'; // 'bubble';
|
node.type = 'circle'; // 'bubble';
|
||||||
node.size = 95;
|
node.size = 95;
|
||||||
if (!node.style) node.style = {};
|
if (!node.style) node.style = {};
|
||||||
node.color = model.color;
|
node.color = model.color;
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
import G6 from '@antv/g6';
|
|
||||||
/**
|
|
||||||
* 该案例演示以下功能:
|
|
||||||
* 1、渲染群组所需要的数据结构;
|
|
||||||
* 2、如何拖动一个群组;
|
|
||||||
* 3、将节点从群组中拖出;
|
|
||||||
* 4、将节点拖入到某个群组中;
|
|
||||||
* 5、拖出拖入节点后动态改变群组大小。
|
|
||||||
*/
|
|
||||||
|
|
||||||
const width = document.getElementById('container').scrollWidth;
|
|
||||||
const height = document.getElementById('container').scrollHeight || 500;
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'container',
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
defaultNode: {
|
|
||||||
type: 'circle',
|
|
||||||
style: {
|
|
||||||
fill: '#DEE9FF',
|
|
||||||
stroke: '#5B8FF9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#e2e2e2',
|
|
||||||
},
|
|
||||||
modes: {
|
|
||||||
default: ['drag-canvas', 'drag-group', 'drag-node-with-group', 'collapse-expand-group'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1-group1',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2-group2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3-group2',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node10',
|
|
||||||
label: 'node10-p2',
|
|
||||||
groupId: 'p2',
|
|
||||||
x: 300,
|
|
||||||
y: 310,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node2',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: 'Group 1',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: -20,
|
|
||||||
offsetY: 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
title: {
|
|
||||||
text: 'Group 2',
|
|
||||||
stroke: '#444',
|
|
||||||
offsetX: -20,
|
|
||||||
offsetY: 30,
|
|
||||||
},
|
|
||||||
parentId: 'p2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p2',
|
|
||||||
title: 'Group 3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"title": {
|
|
||||||
"zh": "中文分类",
|
|
||||||
"en": "Category"
|
|
||||||
},
|
|
||||||
"demos": [
|
|
||||||
{
|
|
||||||
"filename": "circle.js",
|
|
||||||
"title": {
|
|
||||||
"zh": "圆形分组",
|
|
||||||
"en": "Circle Node Group"
|
|
||||||
},
|
|
||||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*S_-uR6WO-ZgAAAAAAAAAAABkARQnAQ"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "rect.js",
|
|
||||||
"title": {
|
|
||||||
"zh": "矩形分组",
|
|
||||||
"en": "Rect Node Group"
|
|
||||||
},
|
|
||||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*DuaCTKCCUAoAAAAAAAAAAABkARQnAQ"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
import G6 from '@antv/g6';
|
|
||||||
/**
|
|
||||||
* 该案例演示以下功能:
|
|
||||||
* 1、渲染群组所需要的数据结构;
|
|
||||||
* 2、如何拖动一个群组;
|
|
||||||
* 3、将节点从群组中拖出;
|
|
||||||
* 4、将节点拖入到某个群组中;
|
|
||||||
* 5、拖出拖入节点后动态改变群组大小。
|
|
||||||
*/
|
|
||||||
|
|
||||||
const width = document.getElementById('container').scrollWidth;
|
|
||||||
const height = document.getElementById('container').scrollHeight || 500;
|
|
||||||
const graph = new G6.Graph({
|
|
||||||
container: 'container',
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
defaultNode: {
|
|
||||||
type: 'circle',
|
|
||||||
style: {
|
|
||||||
fill: '#DEE9FF',
|
|
||||||
stroke: '#5B8FF9',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultEdge: {
|
|
||||||
color: '#e2e2e2',
|
|
||||||
},
|
|
||||||
modes: {
|
|
||||||
default: ['drag-canvas', 'drag-group', 'drag-node-with-group', 'collapse-expand-group'],
|
|
||||||
},
|
|
||||||
groupType: 'rect',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1-group1',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2-group2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3-group2',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node10',
|
|
||||||
label: 'node10-p2',
|
|
||||||
groupId: 'p2',
|
|
||||||
x: 300,
|
|
||||||
y: 310,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node2',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
source: 'node1',
|
|
||||||
target: 'node3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: {
|
|
||||||
text: 'Group 1',
|
|
||||||
stroke: '#444',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
title: {
|
|
||||||
text: 'Group 2',
|
|
||||||
stroke: '#444',
|
|
||||||
},
|
|
||||||
parentId: 'p2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p2',
|
|
||||||
title: 'Group 3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
title: Node Group
|
|
||||||
order: 5
|
|
||||||
---
|
|
||||||
|
|
||||||
G6 supports node group. We recommend to use the new mechanism [Combo](/en/examples/interaction/combo).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
G6 supports two kinds of node group: `circle` and `rect`. They can be applied to group navigation and clustering analysis.
|
|
@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
title: 节点分组 Group
|
|
||||||
order: 5
|
|
||||||
---
|
|
||||||
|
|
||||||
G6 支持节点分组。建议使用新的分组机制 [Combo](/zh/examples/interaction/combo).
|
|
||||||
|
|
||||||
## 使用指南
|
|
||||||
|
|
||||||
G6 默认支持 `circle` 和 `rect` 两种类型的节点分组,可用于团伙导航或聚类分析。
|
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: moyee
|
|
||||||
* @Date: 2019-07-31 14:36:15
|
|
||||||
* @LastEditors: moyee
|
|
||||||
* @LastEditTime: 2019-08-22 18:43:24
|
|
||||||
* @Description: 收起和展开群组
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { G6Event, IG6GraphEvent } from '../types';
|
|
||||||
|
|
||||||
const DEFAULT_TRIGGER = 'dblclick';
|
|
||||||
const ALLOW_EVENTS = ['click', 'dblclick'];
|
|
||||||
export default {
|
|
||||||
getDefaultCfg(): object {
|
|
||||||
return {
|
|
||||||
trigger: DEFAULT_TRIGGER,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getEvents(): { [key in G6Event]?: string } {
|
|
||||||
let trigger: string;
|
|
||||||
// 检测输入是否合法
|
|
||||||
if (ALLOW_EVENTS.includes(this.trigger)) {
|
|
||||||
trigger = this.trigger;
|
|
||||||
} else {
|
|
||||||
trigger = DEFAULT_TRIGGER;
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn(
|
|
||||||
"Behavior collapse-expand-group 的 trigger 参数不合法,请输入 'click' 或 'dblclick'",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
[`${trigger}`]: 'onGroupClick',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onGroupClick(evt: IG6GraphEvent) {
|
|
||||||
const { target } = evt;
|
|
||||||
const { graph } = this;
|
|
||||||
|
|
||||||
const groupId = target.get('groupId');
|
|
||||||
if (!groupId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
customGroupControll.collapseExpandGroup(groupId);
|
|
||||||
},
|
|
||||||
};
|
|
@ -91,7 +91,7 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.keydown || e.shape) {
|
if (self.keydown || e.type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onMouseMove(e: IG6GraphEvent) {
|
onMouseMove(e: IG6GraphEvent) {
|
||||||
const { graph } = this;
|
const { graph } = this;
|
||||||
if (this.keydown || e.shape) {
|
if (this.keydown || e.type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ export default {
|
|||||||
onMouseUp(e: IG6GraphEvent) {
|
onMouseUp(e: IG6GraphEvent) {
|
||||||
const { graph } = this;
|
const { graph } = this;
|
||||||
|
|
||||||
if (this.keydown || e.shape) {
|
if (this.keydown || e.type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: moyee
|
|
||||||
* @Date: 2019-07-31 14:36:15
|
|
||||||
* @LastEditors: moyee
|
|
||||||
* @LastEditTime: 2019-08-23 11:13:43
|
|
||||||
* @Description: 拖动群组
|
|
||||||
*/
|
|
||||||
import deepMix from '@antv/util/lib/deep-mix';
|
|
||||||
import { G6Event, IG6GraphEvent } from '../types';
|
|
||||||
import Global from '../global';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getDefaultCfg(): object {
|
|
||||||
return {
|
|
||||||
delegate: true,
|
|
||||||
delegateStyle: {},
|
|
||||||
delegateShapes: {},
|
|
||||||
delegateShapeBBoxs: {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getEvents(): { [key in G6Event]?: string } {
|
|
||||||
return {
|
|
||||||
dragstart: 'onDragStart',
|
|
||||||
drag: 'onDrag',
|
|
||||||
dragend: 'onDragEnd',
|
|
||||||
'canvas:mouseleave': 'onOutOfRange',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onDragStart(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
const { target } = evt;
|
|
||||||
// 获取拖动的group的ID,如果拖动的不是group,则直接return
|
|
||||||
const groupId: string = target.get('groupId');
|
|
||||||
if (!groupId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const { customGroup } = customGroupControll;
|
|
||||||
|
|
||||||
const currentGroup = customGroup[groupId].nodeGroup;
|
|
||||||
|
|
||||||
this.targetGroup = currentGroup;
|
|
||||||
this.mouseOrigin = {
|
|
||||||
x: evt.x,
|
|
||||||
y: evt.y,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取groupId的父Group的ID
|
|
||||||
const { groups } = graph.save();
|
|
||||||
let parentGroupId = null;
|
|
||||||
|
|
||||||
for (let i = 0; i < groups.length; i++) {
|
|
||||||
const group = groups[i];
|
|
||||||
if (groupId === group.id) {
|
|
||||||
parentGroupId = group.parentId;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentGroupId) {
|
|
||||||
const parentGroup = customGroup[parentGroupId].nodeGroup;
|
|
||||||
customGroupControll.setGroupStyle(parentGroup.get('keyShape'), 'hover');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDrag(evt: IG6GraphEvent) {
|
|
||||||
if (!this.mouseOrigin) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.updateDelegate(evt);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDragEnd(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
// 删除delegate shape
|
|
||||||
const groupId: string = evt.target.get('groupId');
|
|
||||||
if (this.delegateShapes[groupId]) {
|
|
||||||
this.delegateShapeBBox = this.delegateShapes[groupId].getBBox();
|
|
||||||
this.delegateShapes[groupId].remove();
|
|
||||||
delete this.delegateShapes[groupId];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.delegateShapeBBox) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改群组位置
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const delegateShapeBBoxs = this.delegateShapeBBoxs[groupId];
|
|
||||||
customGroupControll.updateGroup(groupId, delegateShapeBBoxs, this.mouseOrigin);
|
|
||||||
|
|
||||||
this.mouseOrigin = null;
|
|
||||||
this.shapeOrigin = null;
|
|
||||||
customGroupControll.resetNodePoint();
|
|
||||||
this.delegateShapeBBox = null;
|
|
||||||
},
|
|
||||||
updateDelegate(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
const groupId: string = evt.target.get('groupId');
|
|
||||||
const item = this.targetGroup.get('keyShape');
|
|
||||||
|
|
||||||
let delegateShape = this.delegateShapes[groupId];
|
|
||||||
const groupBbox = item.getBBox();
|
|
||||||
const delegateType = item.get('type');
|
|
||||||
if (!delegateShape) {
|
|
||||||
const delegateGroup = graph.get('delegateGroup');
|
|
||||||
const { x: bboxX, y: bboxY, width, height } = groupBbox;
|
|
||||||
|
|
||||||
const attrs = {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
...deepMix({}, Global.delegateStyle, this.delegateStyle),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 如果delegate是circle
|
|
||||||
if (delegateType === 'circle') {
|
|
||||||
const r = width > height ? width / 2 : height / 2;
|
|
||||||
const cx = bboxX + r;
|
|
||||||
const cy = bboxY + r;
|
|
||||||
|
|
||||||
delegateShape = delegateGroup.addShape('circle', {
|
|
||||||
attrs: {
|
|
||||||
x: cx,
|
|
||||||
y: cy,
|
|
||||||
r,
|
|
||||||
...attrs,
|
|
||||||
},
|
|
||||||
name: 'circle-delegate-shape',
|
|
||||||
});
|
|
||||||
this.shapeOrigin = { x: cx, y: cy };
|
|
||||||
} else {
|
|
||||||
delegateShape = delegateGroup.addShape('rect', {
|
|
||||||
attrs: {
|
|
||||||
x: bboxX,
|
|
||||||
y: bboxY,
|
|
||||||
...attrs,
|
|
||||||
},
|
|
||||||
name: 'rect-delegate-shape',
|
|
||||||
});
|
|
||||||
this.shapeOrigin = { x: bboxX, y: bboxY };
|
|
||||||
}
|
|
||||||
// delegateShape.set('capture', false);
|
|
||||||
this.delegateShapes[groupId] = delegateShape;
|
|
||||||
this.delegateShapeBBoxs[groupId] = delegateShape.getBBox();
|
|
||||||
} else {
|
|
||||||
const { mouseOrigin, shapeOrigin } = this;
|
|
||||||
const deltaX = evt.x - mouseOrigin.x;
|
|
||||||
const deltaY = evt.y - mouseOrigin.y;
|
|
||||||
const x = deltaX + shapeOrigin.x;
|
|
||||||
const y = deltaY + shapeOrigin.y;
|
|
||||||
|
|
||||||
delegateShape.attr({ x, y });
|
|
||||||
this.delegateShapeBBoxs[groupId] = delegateShape.getBBox();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onOutOfRange(e: IG6GraphEvent) {
|
|
||||||
const canvasElement = this.graph.get('canvas').get('el');
|
|
||||||
const listener = (ev) => {
|
|
||||||
if (ev.target !== canvasElement) {
|
|
||||||
this.onDragEnd(e);
|
|
||||||
// 终止时需要判断此时是否在监听画布外的 mouseup 事件,若有则解绑
|
|
||||||
document.body.removeEventListener('mouseup', listener, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.mouseOrigin) {
|
|
||||||
document.body.addEventListener('mouseup', listener, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,356 +0,0 @@
|
|||||||
import { IG6GraphEvent, Item, G6Event, NodeConfig } from '../types';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @Author: moyee
|
|
||||||
* @Date: 2019-06-27 18:12:06
|
|
||||||
* @LastEditors: moyee
|
|
||||||
* @LastEditTime: 2019-08-23 13:54:53
|
|
||||||
* @Description: 有group的情况下,拖动节点的Behavior
|
|
||||||
*/
|
|
||||||
import deepMix from '@antv/util/lib/deep-mix';
|
|
||||||
import Global from '../global';
|
|
||||||
|
|
||||||
const { body } = document;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getDefaultCfg(): object {
|
|
||||||
return {
|
|
||||||
updateEdge: true,
|
|
||||||
delegate: true,
|
|
||||||
delegateStyle: {},
|
|
||||||
maxMultiple: 1.1,
|
|
||||||
minMultiple: 1,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getEvents(): { [key in G6Event]?: string } {
|
|
||||||
return {
|
|
||||||
'node:dragstart': 'onDragStart',
|
|
||||||
'node:drag': 'onDrag',
|
|
||||||
'node:dragend': 'onDragEnd',
|
|
||||||
'canvas:mouseleave': 'onOutOfRange',
|
|
||||||
dragover: 'onDragOver',
|
|
||||||
// FIXME: does not response
|
|
||||||
dragleave: 'onDragLeave',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onDragOver(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
const { target } = evt;
|
|
||||||
const groupId = target.get('groupId');
|
|
||||||
if (groupId && this.origin) {
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const customGroup = customGroupControll.getDeletageGroupById(groupId);
|
|
||||||
if (customGroup) {
|
|
||||||
const { nodeGroup: currentGroup } = customGroup;
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
|
|
||||||
this.inGroupId = groupId;
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'hover');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 拖动节点移除Group时的事件
|
|
||||||
* @param {Event} evt 事件句柄
|
|
||||||
*/
|
|
||||||
onDragLeave(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
const { target } = evt;
|
|
||||||
const groupId = target.get('groupId');
|
|
||||||
if (groupId && this.origin) {
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
|
|
||||||
const customGroup = customGroupControll.getDeletageGroupById(groupId);
|
|
||||||
if (customGroup) {
|
|
||||||
const { nodeGroup: currentGroup } = customGroup;
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!groupId) {
|
|
||||||
this.inGroupId = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDragStart(e: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
if (!this.shouldBegin.call(this, e)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { item } = e;
|
|
||||||
|
|
||||||
this.target = item;
|
|
||||||
// 拖动节点时,如果在Group中,则Group高亮
|
|
||||||
const model = item.getModel();
|
|
||||||
const { groupId } = model;
|
|
||||||
if (groupId) {
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const customGroup = customGroupControll.getDeletageGroupById(groupId);
|
|
||||||
if (customGroup) {
|
|
||||||
const { nodeGroup: currentGroup } = customGroup;
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'hover');
|
|
||||||
|
|
||||||
// 初始拖动时候,如果是在当前群组中拖动,则赋值为当前groupId
|
|
||||||
this.inGroupId = groupId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.origin = {
|
|
||||||
x: e.x,
|
|
||||||
y: e.y,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.point = {};
|
|
||||||
this.originPoint = {};
|
|
||||||
},
|
|
||||||
onDrag(e: IG6GraphEvent) {
|
|
||||||
if (!this.origin) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.get('shouldUpdate').call(this, e)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update(this.target, e, true);
|
|
||||||
const { item } = e;
|
|
||||||
const { graph } = this;
|
|
||||||
const model = item.getModel();
|
|
||||||
const { groupId } = model;
|
|
||||||
if (groupId) {
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const customGroup = customGroupControll.getDeletageGroupById(groupId);
|
|
||||||
if (customGroup) {
|
|
||||||
const { nodeGroup: currentGroup } = customGroup;
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
|
|
||||||
// 当前
|
|
||||||
if (this.inGroupId !== groupId) {
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
|
||||||
} else {
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'hover');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDragEnd(e: IG6GraphEvent) {
|
|
||||||
if (!this.origin || !this.shouldEnd.call(this, e)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.shape) {
|
|
||||||
this.shape.remove();
|
|
||||||
this.shape = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.target) {
|
|
||||||
const delegateShape = this.target.get('delegateShape');
|
|
||||||
if (delegateShape) {
|
|
||||||
delegateShape.remove();
|
|
||||||
this.target.set('delegateShape', null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.target) {
|
|
||||||
this.update(this.target, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.point = {};
|
|
||||||
this.origin = null;
|
|
||||||
this.originPoint = {};
|
|
||||||
this.target = null;
|
|
||||||
|
|
||||||
this.setCurrentGroupStyle(e);
|
|
||||||
},
|
|
||||||
setCurrentGroupStyle(evt: IG6GraphEvent) {
|
|
||||||
const { graph } = this;
|
|
||||||
const { item } = evt;
|
|
||||||
|
|
||||||
const model = item.getModel() as NodeConfig;
|
|
||||||
// 节点所在的GroupId
|
|
||||||
const { groupId, id } = model;
|
|
||||||
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
|
||||||
const { customGroup } = customGroupControll;
|
|
||||||
const groupNodes = graph.get('groupNodes');
|
|
||||||
if (this.inGroupId && groupId) {
|
|
||||||
const currentGroup = customGroup[groupId].nodeGroup;
|
|
||||||
if (!currentGroup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
|
|
||||||
const itemBBox = item.getBBox();
|
|
||||||
const currentGroupBBox = keyShape.getBBox();
|
|
||||||
|
|
||||||
const { centerX, centerY } = itemBBox;
|
|
||||||
const { minX, minY, maxX, maxY } = currentGroupBBox;
|
|
||||||
|
|
||||||
// 在自己的group中拖动,判断是否拖出了自己的group
|
|
||||||
// this.inGroupId !== groupId,则说明拖出了原来的group,拖到了其他group上面,
|
|
||||||
// 则删除item中的groupId字段,同时删除group中的nodeID
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
centerX < maxX * this.maxMultiple &&
|
|
||||||
centerX > minX * this.minMultiple &&
|
|
||||||
centerY < maxY * this.maxMultiple &&
|
|
||||||
centerY > minY * this.minMultiple
|
|
||||||
) ||
|
|
||||||
this.inGroupId !== groupId
|
|
||||||
) {
|
|
||||||
// 拖出了group,则删除item中的groupId字段,同时删除group中的nodeID
|
|
||||||
const currentGroupNodes = groupNodes[groupId];
|
|
||||||
groupNodes[groupId] = currentGroupNodes.filter((node) => node !== id);
|
|
||||||
|
|
||||||
customGroupControll.dynamicChangeGroupSize(evt, currentGroup, keyShape);
|
|
||||||
|
|
||||||
// 同时删除groupID中的节点
|
|
||||||
delete model.groupId;
|
|
||||||
}
|
|
||||||
// 拖动到其他的group上面
|
|
||||||
if (this.inGroupId !== groupId) {
|
|
||||||
// 拖动新的group后,更新groupNodes及model中的groupId
|
|
||||||
const nodeInGroup = customGroup[this.inGroupId].nodeGroup;
|
|
||||||
if (!nodeInGroup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetKeyShape = nodeInGroup.get('keyShape');
|
|
||||||
// 将该节点添加到inGroupId中
|
|
||||||
if (groupNodes[this.inGroupId].indexOf(id) === -1) {
|
|
||||||
groupNodes[this.inGroupId].push(id);
|
|
||||||
}
|
|
||||||
// 更新节点的groupId为拖动上去的group Id
|
|
||||||
model.groupId = this.inGroupId;
|
|
||||||
|
|
||||||
// 拖入节点后,根据最新的节点数量,重新计算群组大小
|
|
||||||
customGroupControll.dynamicChangeGroupSize(evt, nodeInGroup, targetKeyShape);
|
|
||||||
}
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
|
||||||
} else if (this.inGroupId && !groupId) {
|
|
||||||
// 将节点拖动到群组中
|
|
||||||
const nodeInGroup = customGroup[this.inGroupId].nodeGroup;
|
|
||||||
if (!nodeInGroup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyShape = nodeInGroup.get('keyShape');
|
|
||||||
// 将该节点添加到inGroupId中
|
|
||||||
if (groupNodes[this.inGroupId].indexOf(id) === -1) {
|
|
||||||
groupNodes[this.inGroupId].push(id);
|
|
||||||
}
|
|
||||||
// 更新节点的groupId为拖动上去的group Id
|
|
||||||
model.groupId = this.inGroupId;
|
|
||||||
// 拖入节点后,根据最新的节点数量,重新计算群组大小
|
|
||||||
customGroupControll.dynamicChangeGroupSize(evt, nodeInGroup, keyShape);
|
|
||||||
} else if (!this.inGroupId && groupId) {
|
|
||||||
// 拖出到群组之外了,则删除数据中的groupId
|
|
||||||
Object.keys(groupNodes).forEach((gnode) => {
|
|
||||||
const currentGroupNodes = groupNodes[gnode];
|
|
||||||
groupNodes[gnode] = currentGroupNodes.filter((node) => node !== id);
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentGroup = customGroup[groupId].nodeGroup;
|
|
||||||
if (!currentGroup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyShape = currentGroup.get('keyShape');
|
|
||||||
customGroupControll.dynamicChangeGroupSize(evt, currentGroup, keyShape);
|
|
||||||
delete model.groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inGroupId = null;
|
|
||||||
},
|
|
||||||
// 若在拖拽时,鼠标移出画布区域,此时放开鼠标无法终止 drag 行为。在画布外监听 mouseup 事件,放开则终止
|
|
||||||
onOutOfRange(e: IG6GraphEvent) {
|
|
||||||
const self = this;
|
|
||||||
const canvasElement = self.graph.get('canvas').get('el');
|
|
||||||
function listener(ev) {
|
|
||||||
if (ev.target !== canvasElement) {
|
|
||||||
e.item = self.target;
|
|
||||||
self.onDragEnd(e);
|
|
||||||
// 终止时需要判断此时是否在监听画布外的 mouseup 事件,若有则解绑
|
|
||||||
document.body.removeEventListener('mouseup', listener, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (self.origin) {
|
|
||||||
body.addEventListener('mouseup', listener, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update(item: Item, e: IG6GraphEvent, force: boolean) {
|
|
||||||
const { origin } = this;
|
|
||||||
const model = item.get('model');
|
|
||||||
const nodeId = item.get('id');
|
|
||||||
if (!this.point[nodeId]) {
|
|
||||||
this.point[nodeId] = {
|
|
||||||
x: model.x,
|
|
||||||
y: model.y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const x = e.x - origin.x + this.point[nodeId].x;
|
|
||||||
const y = e.y - origin.y + this.point[nodeId].y;
|
|
||||||
|
|
||||||
// 拖动单个未选中元素
|
|
||||||
if (force) {
|
|
||||||
this.updateDelegate(e, x, y);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pos = { x, y };
|
|
||||||
|
|
||||||
if (this.get('updateEdge')) {
|
|
||||||
this.graph.updateItem(item, pos);
|
|
||||||
} else {
|
|
||||||
item.updatePosition(pos);
|
|
||||||
this.graph.paint();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 更新拖动元素时的delegate
|
|
||||||
* @param {Event} e 事件句柄
|
|
||||||
* @param {number} x 拖动单个元素时候的x坐标
|
|
||||||
* @param {number} y 拖动单个元素时候的y坐标
|
|
||||||
*/
|
|
||||||
updateDelegate(e: IG6GraphEvent, x: number, y: number) {
|
|
||||||
const { graph } = this;
|
|
||||||
const { item } = e;
|
|
||||||
const groupType = graph.get('groupType');
|
|
||||||
const bbox = item.get('keyShape').getBBox();
|
|
||||||
if (!this.shape) {
|
|
||||||
const parent = graph.get('delegateGroup');
|
|
||||||
const attrs = deepMix({}, Global.delegateStyle, this.delegateStyle);
|
|
||||||
if (this.target) {
|
|
||||||
this.shape = parent.addShape('rect', {
|
|
||||||
attrs: {
|
|
||||||
width: bbox.width,
|
|
||||||
height: bbox.height,
|
|
||||||
x: x - bbox.width / 2,
|
|
||||||
y: y - bbox.height / 2,
|
|
||||||
...attrs,
|
|
||||||
},
|
|
||||||
name: 'delegate-shape',
|
|
||||||
});
|
|
||||||
this.target.set('delegateShape', this.shape);
|
|
||||||
}
|
|
||||||
this.shape.set('capture', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.target) {
|
|
||||||
if (groupType === 'circle') {
|
|
||||||
this.shape.attr({
|
|
||||||
x: x - bbox.width / 2,
|
|
||||||
y: y - bbox.height / 2,
|
|
||||||
});
|
|
||||||
} else if (groupType === 'rect') {
|
|
||||||
this.shape.attr({
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
@ -8,9 +8,6 @@ import ClickSelect from './click-select';
|
|||||||
import ZoomCanvas from './zoom-canvas';
|
import ZoomCanvas from './zoom-canvas';
|
||||||
import Tooltip from './tooltip';
|
import Tooltip from './tooltip';
|
||||||
import EdgeTooltip from './edge-tooltip';
|
import EdgeTooltip from './edge-tooltip';
|
||||||
import DragGroup from './drag-group';
|
|
||||||
import DragNodeWidthGroup from './drag-node-with-group';
|
|
||||||
import CollapseExpandGroup from './collapse-expand-group';
|
|
||||||
import CollapseExpand from './collapse-expand';
|
import CollapseExpand from './collapse-expand';
|
||||||
import DragCombo from './drag-combo';
|
import DragCombo from './drag-combo';
|
||||||
import CollapseExpandCombo from './collapse-expand-combo';
|
import CollapseExpandCombo from './collapse-expand-combo';
|
||||||
@ -28,9 +25,6 @@ const behaviors = {
|
|||||||
'lasso-select': LassoSelect,
|
'lasso-select': LassoSelect,
|
||||||
tooltip: Tooltip,
|
tooltip: Tooltip,
|
||||||
'edge-tooltip': EdgeTooltip,
|
'edge-tooltip': EdgeTooltip,
|
||||||
'drag-group': DragGroup,
|
|
||||||
'drag-node-with-group': DragNodeWidthGroup,
|
|
||||||
'collapse-expand-group': CollapseExpandGroup,
|
|
||||||
'collapse-expand': CollapseExpand,
|
'collapse-expand': CollapseExpand,
|
||||||
'drag-combo': DragCombo,
|
'drag-combo': DragCombo,
|
||||||
'collapse-expand-combo': CollapseExpandCombo,
|
'collapse-expand-combo': CollapseExpandCombo,
|
||||||
|
@ -247,7 +247,7 @@ export default {
|
|||||||
const itemStateStyle = node.getStateStyle(fixSelectedItems.fixState);
|
const itemStateStyle = node.getStateStyle(fixSelectedItems.fixState);
|
||||||
const shapeStateStyle = node
|
const shapeStateStyle = node
|
||||||
.get('shapeFactory')
|
.get('shapeFactory')
|
||||||
.getShape(nodeModel.shape || nodeModel.type)
|
.getShape(nodeModel.type)
|
||||||
.getStateStyle(fixSelectedItems.fixState, node)[fixSelectedItems.fixState];
|
.getStateStyle(fixSelectedItems.fixState, node)[fixSelectedItems.fixState];
|
||||||
if (fixSelectedItems.fixAll) {
|
if (fixSelectedItems.fixAll) {
|
||||||
if (zoom <= 1) {
|
if (zoom <= 1) {
|
||||||
@ -299,7 +299,7 @@ export default {
|
|||||||
const itemStateStyle = edge.getStateStyle(fixSelectedItems.fixState);
|
const itemStateStyle = edge.getStateStyle(fixSelectedItems.fixState);
|
||||||
const shapeStateStyle = edge
|
const shapeStateStyle = edge
|
||||||
.get('shapeFactory')
|
.get('shapeFactory')
|
||||||
.getShape(nodeModel.shape || nodeModel.type)
|
.getShape(nodeModel.type)
|
||||||
.getStateStyle(fixSelectedItems.fixState, edge)[fixSelectedItems.fixState];
|
.getStateStyle(fixSelectedItems.fixState, edge)[fixSelectedItems.fixState];
|
||||||
|
|
||||||
const childrenLength = children.length;
|
const childrenLength = children.length;
|
||||||
|
@ -12,7 +12,6 @@ export default {
|
|||||||
nodeContainerClassName: 'node-container',
|
nodeContainerClassName: 'node-container',
|
||||||
edgeContainerClassName: 'edge-container',
|
edgeContainerClassName: 'edge-container',
|
||||||
comboContainerClassName: 'combo-container',
|
comboContainerClassName: 'combo-container',
|
||||||
customGroupContainerClassName: 'custom-group-container',
|
|
||||||
delegateContainerClassName: 'delegate-container',
|
delegateContainerClassName: 'delegate-container',
|
||||||
defaultLoopPosition: 'top',
|
defaultLoopPosition: 'top',
|
||||||
nodeLabel: {
|
nodeLabel: {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,4 +4,3 @@ export { default as EventController } from './event';
|
|||||||
export { default as ItemController } from './item';
|
export { default as ItemController } from './item';
|
||||||
export { default as LayoutController } from './layout';
|
export { default as LayoutController } from './layout';
|
||||||
export { default as StateController } from './state';
|
export { default as StateController } from './state';
|
||||||
export { default as CustomGroup } from './customGroup';
|
|
||||||
|
@ -93,10 +93,6 @@ export default class ItemController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.shape && !model.type) {
|
|
||||||
console.warn('shape 字段即将被废弃,请使用 type 代替');
|
|
||||||
}
|
|
||||||
|
|
||||||
graph.emit('beforeadditem', { type, model });
|
graph.emit('beforeadditem', { type, model });
|
||||||
|
|
||||||
if (type === EDGE || type === VEDGE) {
|
if (type === EDGE || type === VEDGE) {
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
GraphOptions,
|
GraphOptions,
|
||||||
EdgeConfig,
|
EdgeConfig,
|
||||||
GraphData,
|
GraphData,
|
||||||
GroupConfig,
|
|
||||||
Item,
|
Item,
|
||||||
ITEM_TYPE,
|
ITEM_TYPE,
|
||||||
Matrix,
|
Matrix,
|
||||||
@ -29,11 +28,9 @@ import {
|
|||||||
HullCfg,
|
HullCfg,
|
||||||
WaterMarkerConfig,
|
WaterMarkerConfig,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { getAllNodeInGroups } from '../util/group';
|
|
||||||
import { move } from '../util/math';
|
import { move } from '../util/math';
|
||||||
import Global from '../global';
|
import Global from '../global';
|
||||||
import {
|
import {
|
||||||
CustomGroup,
|
|
||||||
EventController,
|
EventController,
|
||||||
ItemController,
|
ItemController,
|
||||||
LayoutController,
|
LayoutController,
|
||||||
@ -70,18 +67,12 @@ export interface PrivateGraphOption extends GraphOptions {
|
|||||||
|
|
||||||
vedges: EdgeConfig[];
|
vedges: EdgeConfig[];
|
||||||
|
|
||||||
groups: GroupConfig[];
|
|
||||||
|
|
||||||
combos: ComboConfig[];
|
combos: ComboConfig[];
|
||||||
|
|
||||||
itemMap: NodeMap;
|
itemMap: NodeMap;
|
||||||
|
|
||||||
callback: () => void;
|
callback: () => void;
|
||||||
|
|
||||||
groupBBoxs: IGroupBBox;
|
|
||||||
|
|
||||||
groupNodes: NodeMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式:
|
* 格式:
|
||||||
* {
|
* {
|
||||||
@ -130,7 +121,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
const itemController = new ItemController(this);
|
const itemController = new ItemController(this);
|
||||||
const layoutController = new LayoutController(this);
|
const layoutController = new LayoutController(this);
|
||||||
const stateController = new StateController(this);
|
const stateController = new StateController(this);
|
||||||
const customGroupControll = new CustomGroup(this);
|
|
||||||
|
|
||||||
this.set({
|
this.set({
|
||||||
eventController,
|
eventController,
|
||||||
@ -139,7 +129,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
itemController,
|
itemController,
|
||||||
layoutController,
|
layoutController,
|
||||||
stateController,
|
stateController,
|
||||||
customGroupControll,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.initPlugin();
|
this.initPlugin();
|
||||||
@ -223,15 +212,9 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 用于存储自定义的群组
|
// 用于存储自定义的群组
|
||||||
const customGroup: IGroup = group.addGroup({
|
|
||||||
id: `${id}-group`,
|
|
||||||
className: Global.customGroupContainerClassName,
|
|
||||||
});
|
|
||||||
|
|
||||||
customGroup.toBack();
|
|
||||||
comboGroup.toBack();
|
comboGroup.toBack();
|
||||||
|
|
||||||
this.set({ nodeGroup, edgeGroup, customGroup, comboGroup });
|
this.set({ nodeGroup, edgeGroup, comboGroup });
|
||||||
}
|
}
|
||||||
const delegateGroup: IGroup = group.addGroup({
|
const delegateGroup: IGroup = group.addGroup({
|
||||||
id: `${id}-delegate`,
|
id: `${id}-delegate`,
|
||||||
@ -391,28 +374,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
easing: 'easeLinear',
|
easing: 'easeLinear',
|
||||||
},
|
},
|
||||||
callback: undefined,
|
callback: undefined,
|
||||||
/**
|
|
||||||
* group类型
|
|
||||||
*/
|
|
||||||
groupType: 'circle',
|
|
||||||
/**
|
|
||||||
* group bbox 对象
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
groupBBoxs: {},
|
|
||||||
/**
|
|
||||||
* 以groupid分组的节点数据
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
groupNodes: {},
|
|
||||||
/**
|
|
||||||
* group 数据
|
|
||||||
*/
|
|
||||||
groups: [],
|
|
||||||
/**
|
|
||||||
* group样式
|
|
||||||
*/
|
|
||||||
groupStyle: {},
|
|
||||||
|
|
||||||
// 默认不启用 undo & redo 功能
|
// 默认不启用 undo & redo 功能
|
||||||
enabledStack: false,
|
enabledStack: false,
|
||||||
@ -947,14 +908,11 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
||||||
*/
|
*/
|
||||||
public removeItem(item: Item | string, stack: boolean = true): void {
|
public removeItem(item: Item | string, stack: boolean = true): void {
|
||||||
// 如果item是字符串,且查询的节点实例不存在,则认为是删除group
|
|
||||||
let nodeItem = item;
|
let nodeItem = item;
|
||||||
if (isString(item)) nodeItem = this.findById(item);
|
if (isString(item)) nodeItem = this.findById(item);
|
||||||
|
|
||||||
if (!nodeItem && isString(item)) {
|
if (!nodeItem && isString(item)) {
|
||||||
console.warn('The item to be removed does not exist!');
|
console.warn('The item to be removed does not exist!');
|
||||||
const customGroupControll: CustomGroup = this.get('customGroupControll');
|
|
||||||
customGroupControll.remove(item);
|
|
||||||
} else if (nodeItem) {
|
} else if (nodeItem) {
|
||||||
let type = '';
|
let type = '';
|
||||||
if ((nodeItem as Item).getType) type = (nodeItem as Item).getType();
|
if ((nodeItem as Item).getType) type = (nodeItem as Item).getType();
|
||||||
@ -1003,8 +961,8 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增元素 或 节点分组
|
* 新增元素
|
||||||
* @param {ITEM_TYPE} type 元素类型(node | edge | group)
|
* @param {ITEM_TYPE} type 元素类型(node | edge)
|
||||||
* @param {ModelConfig} model 元素数据模型
|
* @param {ModelConfig} model 元素数据模型
|
||||||
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
||||||
* @param {boolean} sortCombo 本次操作是否需要更新 combo 层级顺序,内部参数,用户在外部使用 addItem 时始终时需要更新
|
* @param {boolean} sortCombo 本次操作是否需要更新 combo 层级顺序,内部参数,用户在外部使用 addItem 时始终时需要更新
|
||||||
@ -1014,25 +972,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
const currentComboSorted = this.get('comboSorted');
|
const currentComboSorted = this.get('comboSorted');
|
||||||
this.set('comboSorted', currentComboSorted && !sortCombo);
|
this.set('comboSorted', currentComboSorted && !sortCombo);
|
||||||
const itemController: ItemController = this.get('itemController');
|
const itemController: ItemController = this.get('itemController');
|
||||||
if (type === 'group') {
|
|
||||||
const { groupId, nodes, type: groupType, zIndex, title } = model;
|
|
||||||
let groupTitle = title;
|
|
||||||
|
|
||||||
if (isString(title)) {
|
|
||||||
groupTitle = {
|
|
||||||
text: title,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.get('customGroupControll').create(
|
|
||||||
groupId,
|
|
||||||
nodes,
|
|
||||||
groupType,
|
|
||||||
zIndex,
|
|
||||||
true,
|
|
||||||
groupTitle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.id && this.findById(model.id as string)) {
|
if (model.id && this.findById(model.id as string)) {
|
||||||
console.warn(`This item exists already. Be sure the id %c${model.id}%c is unique.`, 'font-size: 20px; color: red;', '');
|
console.warn(`This item exists already. Be sure the id %c${model.id}%c is unique.`, 'font-size: 20px; color: red;', '');
|
||||||
@ -1164,8 +1103,8 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增元素 或 节点分组
|
* 新增元素
|
||||||
* @param {ITEM_TYPE} type 元素类型(node | edge | group)
|
* @param {ITEM_TYPE} type 元素类型(node | edge)
|
||||||
* @param {ModelConfig} model 元素数据模型
|
* @param {ModelConfig} model 元素数据模型
|
||||||
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
||||||
* @return {Item} 元素实例
|
* @return {Item} 元素实例
|
||||||
@ -1377,19 +1316,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 防止传入的数据不存在nodes
|
|
||||||
if (data.nodes) {
|
|
||||||
// 获取所有有groupID的node
|
|
||||||
const nodeInGroup = data.nodes.filter((node) => node.groupId);
|
|
||||||
|
|
||||||
// 所有node中存在groupID,则说明需要群组
|
|
||||||
if (nodeInGroup.length > 0) {
|
|
||||||
// 渲染群组
|
|
||||||
const groupType = self.get('groupType');
|
|
||||||
this.renderCustomGroup(data, groupType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.get('enabledStack')) {
|
if (this.get('enabledStack')) {
|
||||||
this.pushStack('render');
|
this.pushStack('render');
|
||||||
}
|
}
|
||||||
@ -1888,58 +1814,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
this.updateCombos();
|
this.updateCombos();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据数据渲染群组
|
|
||||||
* @param {GraphData} data 渲染图的数据
|
|
||||||
* @param {string} groupType group类型
|
|
||||||
*/
|
|
||||||
public renderCustomGroup(data: GraphData, groupType: string) {
|
|
||||||
const { groups, nodes = [] } = data;
|
|
||||||
|
|
||||||
// 第一种情况,,不存在groups,则不存在嵌套群组
|
|
||||||
let groupIndex = 10;
|
|
||||||
if (!groups) {
|
|
||||||
// 存在单个群组
|
|
||||||
// 获取所有有groupID的node
|
|
||||||
const nodeInGroup = nodes.filter((node) => node.groupId);
|
|
||||||
const groupsArr: GroupConfig[] = [];
|
|
||||||
// 根据groupID分组
|
|
||||||
const groupIds = groupBy(nodeInGroup, 'groupId');
|
|
||||||
// tslint:disable-next-line:forin
|
|
||||||
Object.keys(groupIds).forEach((groupId) => {
|
|
||||||
const nodeIds = groupIds[groupId].map((node) => node.id);
|
|
||||||
this.get('customGroupControll').create(groupId, nodeIds, groupType, groupIndex);
|
|
||||||
groupIndex--;
|
|
||||||
// 获取所有不重复的 groupId
|
|
||||||
if (!groupsArr.find((d) => d.id === groupId)) {
|
|
||||||
groupsArr.push({
|
|
||||||
id: groupId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.set({
|
|
||||||
groups: groupsArr,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 将groups的数据存到groups中
|
|
||||||
this.set({ groups });
|
|
||||||
|
|
||||||
// 第二种情况,存在嵌套的群组,数据中有groups字段
|
|
||||||
const groupNodes = getAllNodeInGroups(data);
|
|
||||||
// tslint:disable-next-line:forin
|
|
||||||
Object.keys(groupNodes).forEach((groupId) => {
|
|
||||||
const tmpNodes = groupNodes[groupId];
|
|
||||||
this.get('customGroupControll').create(groupId, tmpNodes, groupType, groupIndex);
|
|
||||||
groupIndex--;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 对所有Group排序
|
|
||||||
const customGroup = this.get('customGroup');
|
|
||||||
customGroup.sort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出图数据
|
* 导出图数据
|
||||||
* @return {object} data
|
* @return {object} data
|
||||||
@ -1960,7 +1834,7 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
combos.push(combo.getModel() as ComboConfig);
|
combos.push(combo.getModel() as ComboConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
return { nodes, edges, combos, groups: this.get('groups') };
|
return { nodes, edges, combos };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3004,24 +2878,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
this.updateCombo(combo);
|
this.updateCombo(combo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 收起分组
|
|
||||||
* @param {string} groupId 分组ID
|
|
||||||
*/
|
|
||||||
public collapseGroup(groupId: string): void {
|
|
||||||
const customGroupControll: CustomGroup = this.get('customGroupControll');
|
|
||||||
customGroupControll.collapseGroup(groupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 展开分组
|
|
||||||
* @param {string} groupId 分组ID
|
|
||||||
*/
|
|
||||||
public expandGroup(groupId: string): void {
|
|
||||||
const customGroupControll: CustomGroup = this.get('customGroupControll');
|
|
||||||
customGroupControll.expandGroup(groupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加插件
|
* 添加插件
|
||||||
* @param {object} plugin 插件实例
|
* @param {object} plugin 插件实例
|
||||||
@ -3279,7 +3135,6 @@ export default class Graph extends EventEmitter implements IGraph {
|
|||||||
this.get('viewController').destroy();
|
this.get('viewController').destroy();
|
||||||
this.get('stateController').destroy();
|
this.get('stateController').destroy();
|
||||||
this.get('layoutController').destroy();
|
this.get('layoutController').destroy();
|
||||||
this.get('customGroupControll').destroy();
|
|
||||||
this.get('canvas').destroy();
|
this.get('canvas').destroy();
|
||||||
|
|
||||||
if (this.get('graphWaterMarker')) {
|
if (this.get('graphWaterMarker')) {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { version } from '../package.json';
|
|
||||||
import Behaviors from './behavior';
|
import Behaviors from './behavior';
|
||||||
import Graph from './graph/graph';
|
import Graph from './graph/graph';
|
||||||
import TreeGraph from './graph/tree-graph';
|
import TreeGraph from './graph/tree-graph';
|
||||||
@ -50,7 +49,7 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
version,
|
version: Global.version,
|
||||||
Graph,
|
Graph,
|
||||||
TreeGraph,
|
TreeGraph,
|
||||||
Util,
|
Util,
|
||||||
|
@ -195,8 +195,8 @@ export interface IGraph extends EventEmitter {
|
|||||||
remove(item: Item | string, stack?: boolean): void;
|
remove(item: Item | string, stack?: boolean): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增元素 或 节点分组
|
* 新增元素
|
||||||
* @param {string} type 元素类型(node | edge | group)
|
* @param {string} type 元素类型(node | edge)
|
||||||
* @param {ModelConfig} model 元素数据模型
|
* @param {ModelConfig} model 元素数据模型
|
||||||
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
* @param {boolean} stack 本次操作是否入栈,默认为 true
|
||||||
* @return {Item} 元素实例
|
* @return {Item} 元素实例
|
||||||
@ -357,13 +357,6 @@ export interface IGraph extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
clear(): Graph;
|
clear(): Graph;
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据数据渲染群组
|
|
||||||
* @param {GraphData} data 渲染图的数据
|
|
||||||
* @param {string} groupType group类型
|
|
||||||
*/
|
|
||||||
renderCustomGroup(data: GraphData, groupType: string): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收数据进行渲染
|
* 接收数据进行渲染
|
||||||
* @Param {GraphData} data 初始化数据
|
* @Param {GraphData} data 初始化数据
|
||||||
@ -545,18 +538,6 @@ export interface IGraph extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
collapseExpandCombo(combo: string | ICombo): void;
|
collapseExpandCombo(combo: string | ICombo): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 收起分组
|
|
||||||
* @param {string} groupId 分组ID
|
|
||||||
*/
|
|
||||||
collapseGroup(groupId: string): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 展开分组
|
|
||||||
* @param {string} groupId 分组ID
|
|
||||||
*/
|
|
||||||
expandGroup(groupId: string): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据节点的 bbox 更新所有 combos 的绘制,包括 combos 的位置和范围
|
* 根据节点的 bbox 更新所有 combos 的绘制,包括 combos 的位置和范围
|
||||||
*/
|
*/
|
||||||
|
@ -106,7 +106,7 @@ export default class Edge extends Item implements IEdge {
|
|||||||
const sourcePoint = this.getEndPoint('source');
|
const sourcePoint = this.getEndPoint('source');
|
||||||
const targetPoint = this.getEndPoint('target');
|
const targetPoint = this.getEndPoint('target');
|
||||||
const shapeFactory = this.get('shapeFactory');
|
const shapeFactory = this.get('shapeFactory');
|
||||||
const type = model.shape || model.type;
|
const type = model.type;
|
||||||
return shapeFactory.getControlPoints(type, {
|
return shapeFactory.getControlPoints(type, {
|
||||||
startPoint: sourcePoint,
|
startPoint: sourcePoint,
|
||||||
endPoint: targetPoint,
|
endPoint: targetPoint,
|
||||||
|
@ -183,7 +183,7 @@ export default class ItemBase implements IItemBase {
|
|||||||
}
|
}
|
||||||
self.updatePosition(model);
|
self.updatePosition(model);
|
||||||
const cfg = self.getShapeCfg(model); // 可能会附加额外信息
|
const cfg = self.getShapeCfg(model); // 可能会附加额外信息
|
||||||
const shapeType = (cfg.shape as string) || (cfg.type as string);
|
const shapeType = (cfg.type as string);
|
||||||
|
|
||||||
const keyShape: IShapeBase = shapeFactory.draw(shapeType, cfg, group);
|
const keyShape: IShapeBase = shapeFactory.draw(shapeType, cfg, group);
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ export default class ItemBase implements IItemBase {
|
|||||||
|
|
||||||
if (shapeFactory) {
|
if (shapeFactory) {
|
||||||
const model: ModelConfig = this.get('model');
|
const model: ModelConfig = this.get('model');
|
||||||
const type = model.shape || model.type;
|
const type = model.type;
|
||||||
|
|
||||||
// 调用 shape/shape.ts 中的 setState
|
// 调用 shape/shape.ts 中的 setState
|
||||||
shapeFactory.setState(type, state, value, this);
|
shapeFactory.setState(type, state, value, this);
|
||||||
@ -436,7 +436,7 @@ export default class ItemBase implements IItemBase {
|
|||||||
const originStates = self.getStates();
|
const originStates = self.getStates();
|
||||||
const shapeFactory = self.get('shapeFactory');
|
const shapeFactory = self.get('shapeFactory');
|
||||||
const model: ModelConfig = self.get('model');
|
const model: ModelConfig = self.get('model');
|
||||||
const shape = model.shape || model.type;
|
const shape = model.type;
|
||||||
if (!states) {
|
if (!states) {
|
||||||
states = originStates;
|
states = originStates;
|
||||||
}
|
}
|
||||||
@ -587,7 +587,7 @@ export default class ItemBase implements IItemBase {
|
|||||||
public updateShape() {
|
public updateShape() {
|
||||||
const shapeFactory = this.get('shapeFactory');
|
const shapeFactory = this.get('shapeFactory');
|
||||||
const model = this.get('model');
|
const model = this.get('model');
|
||||||
const shape = model.shape || model.type;
|
const shape = model.type;
|
||||||
// 判定是否允许更新
|
// 判定是否允许更新
|
||||||
// 1. 注册的节点允许更新
|
// 1. 注册的节点允许更新
|
||||||
// 2. 更新后的 shape 等于原先的 shape
|
// 2. 更新后的 shape 等于原先的 shape
|
||||||
|
@ -176,7 +176,7 @@ export default class Node extends Item implements INode {
|
|||||||
const bbox = this.getBBox();
|
const bbox = this.getBBox();
|
||||||
const model: NodeConfig = this.get('model');
|
const model: NodeConfig = this.get('model');
|
||||||
const shapeCfg = this.getShapeCfg(model);
|
const shapeCfg = this.getShapeCfg(model);
|
||||||
const type = model.shape || model.type;
|
const type = model.type;
|
||||||
const points = shapeFactory.getAnchorPoints(type, shapeCfg) || [];
|
const points = shapeFactory.getAnchorPoints(type, shapeCfg) || [];
|
||||||
|
|
||||||
each(points, (pointArr, index) => {
|
each(points, (pointArr, index) => {
|
||||||
|
@ -113,7 +113,7 @@ export default class DagreLayout extends BaseLayout {
|
|||||||
g.edges().forEach((edge: any) => {
|
g.edges().forEach((edge: any) => {
|
||||||
coord = g.edge(edge);
|
coord = g.edge(edge);
|
||||||
const i = edges.findIndex((it) => it.source === edge.v && it.target === edge.w);
|
const i = edges.findIndex((it) => it.source === edge.v && it.target === edge.w);
|
||||||
if (self.controlPoints && edges[i].type !== 'loop' && edges[i].shape !== 'loop') {
|
if (self.controlPoints && edges[i].type !== 'loop') {
|
||||||
edges[i].controlPoints = coord.points.slice(1, coord.points.length - 1);
|
edges[i].controlPoints = coord.points.slice(1, coord.points.length - 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -160,7 +160,6 @@ export default class Bundling extends Base {
|
|||||||
// change the edges according to edgePoints
|
// change the edges according to edgePoints
|
||||||
edges.forEach((e, i) => {
|
edges.forEach((e, i) => {
|
||||||
if (e.source === e.target) return;
|
if (e.source === e.target) return;
|
||||||
e.shape = 'polyline';
|
|
||||||
e.type = 'polyline';
|
e.type = 'polyline';
|
||||||
e.controlPoints = edgePoints[i].slice(1, edgePoints[i].length - 1);
|
e.controlPoints = edgePoints[i].slice(1, edgePoints[i].length - 1);
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,6 @@ import Graph from '../../graph/graph';
|
|||||||
import { IG6GraphEvent, Item } from '../../types';
|
import { IG6GraphEvent, Item } from '../../types';
|
||||||
import Base, { IPluginBaseConfig } from '../base';
|
import Base, { IPluginBaseConfig } from '../base';
|
||||||
import { IGraph } from '../../interface/graph';
|
import { IGraph } from '../../interface/graph';
|
||||||
import edgeTooltip from '../../behavior/edge-tooltip';
|
|
||||||
|
|
||||||
insertCss(`
|
insertCss(`
|
||||||
.g6-component-tooltip {
|
.g6-component-tooltip {
|
||||||
|
@ -366,8 +366,6 @@ export type Easeing =
|
|||||||
| string;
|
| string;
|
||||||
|
|
||||||
export interface ModelConfig extends ModelStyle {
|
export interface ModelConfig extends ModelStyle {
|
||||||
// ⚠️ 节点或边的类型,后续会废弃
|
|
||||||
shape?: string;
|
|
||||||
// 节点或边的类型
|
// 节点或边的类型
|
||||||
type?: string;
|
type?: string;
|
||||||
label?: string | LabelStyle;
|
label?: string | LabelStyle;
|
||||||
@ -533,17 +531,9 @@ export interface NodeConfigMap {
|
|||||||
[key: string]: NodeConfig;
|
[key: string]: NodeConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupConfig {
|
|
||||||
id: string;
|
|
||||||
parentId?: string;
|
|
||||||
[key: string]: string | ModelStyle | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
nodes?: NodeConfig[];
|
nodes?: NodeConfig[];
|
||||||
edges?: EdgeConfig[];
|
edges?: EdgeConfig[];
|
||||||
groups?: GroupConfig[];
|
|
||||||
combos?: ComboConfig[];
|
combos?: ComboConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,8 +544,6 @@ export interface GraphAnimateConfig extends AnimateCfg {
|
|||||||
onFrame?: (item: Item, ratio: number, data?: GraphData, originAttrs?: ShapeStyle) => unknown;
|
onFrame?: (item: Item, ratio: number, data?: GraphData, originAttrs?: ShapeStyle) => unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// export type ModelConfig = NodeConfig | EdgeConfig | GroupConfig
|
|
||||||
|
|
||||||
export interface GroupNodeIds {
|
export interface GroupNodeIds {
|
||||||
[key: string]: string[];
|
[key: string]: string[];
|
||||||
}
|
}
|
||||||
@ -724,7 +712,7 @@ export interface BehaviorOption {
|
|||||||
export type IEvent = Record<G6Event, string>;
|
export type IEvent = Record<G6Event, string>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export type ITEM_TYPE = 'node' | 'edge' | 'combo' | 'group' | 'vedge';
|
export type ITEM_TYPE = 'node' | 'edge' | 'combo' | 'vedge';
|
||||||
|
|
||||||
export type NodeIdxMap = {
|
export type NodeIdxMap = {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
import groupBy, { ObjectType } from '@antv/util/lib/group-by';
|
|
||||||
import { GraphData, GroupConfig, GroupNodeIds } from '../types';
|
|
||||||
|
|
||||||
export const getAllNodeInGroups = (data: GraphData): GroupNodeIds => {
|
|
||||||
const groupById: ObjectType<GroupConfig> = groupBy(data.groups!, 'id');
|
|
||||||
const groupByParentId: ObjectType<GroupConfig> = groupBy(data.groups!, 'parentId');
|
|
||||||
|
|
||||||
const result: { [key: string]: GroupConfig[] } = {};
|
|
||||||
|
|
||||||
for (const parentId in groupByParentId) {
|
|
||||||
if (!parentId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 获取当前parentId的所有子group ID
|
|
||||||
const subGroupIds = groupByParentId[parentId];
|
|
||||||
|
|
||||||
// 获取在parentid群组中的节点
|
|
||||||
const nodeInParentGroup = groupById[parentId];
|
|
||||||
|
|
||||||
if (nodeInParentGroup && subGroupIds) {
|
|
||||||
// 合并
|
|
||||||
const parentGroupNodes = [...subGroupIds, ...nodeInParentGroup];
|
|
||||||
result[parentId] = parentGroupNodes;
|
|
||||||
} else if (subGroupIds) {
|
|
||||||
result[parentId] = subGroupIds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const allGroupsId = { ...groupById, ...result };
|
|
||||||
|
|
||||||
// 缓存所有group包括的groupID
|
|
||||||
const groupIds: { [key: string]: string[] } = {};
|
|
||||||
for (const groupId in allGroupsId) {
|
|
||||||
if (!groupId || groupId === 'undefined') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const subGroupIds = allGroupsId[groupId].map((node) => node.id);
|
|
||||||
|
|
||||||
// const nodesInGroup = data.nodes.filter(node => node.groupId === groupId).map(node => node.id);
|
|
||||||
groupIds[groupId] = subGroupIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存所有groupID对应的Node
|
|
||||||
const groupNodes: GroupNodeIds = {} as GroupNodeIds;
|
|
||||||
for (const groupId in groupIds) {
|
|
||||||
if (!groupId || groupId === 'undefined') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subGroupIds = groupIds[groupId];
|
|
||||||
|
|
||||||
// const subGroupIds = allGroupsId[groupId].map(node => node.id);
|
|
||||||
|
|
||||||
// 解析所有子群组
|
|
||||||
const parentSubGroupIds: string[] = [];
|
|
||||||
|
|
||||||
for (const subId of subGroupIds) {
|
|
||||||
const tmpGroupId = allGroupsId[subId].map((node) => node.id);
|
|
||||||
// const tmpNodes = data.nodes.filter(node => node.groupId === subId).map(node => node.id);
|
|
||||||
parentSubGroupIds.push(...tmpGroupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nodesInGroup = data.nodes
|
|
||||||
? data.nodes
|
|
||||||
.filter(
|
|
||||||
(node) =>
|
|
||||||
parentSubGroupIds.indexOf(node.groupId!) > -1 ||
|
|
||||||
parentSubGroupIds.indexOf(node.parentId as string) > -1,
|
|
||||||
)
|
|
||||||
.map((node) => node.id)
|
|
||||||
: [];
|
|
||||||
groupNodes[groupId] = nodesInGroup;
|
|
||||||
}
|
|
||||||
return groupNodes;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -86,9 +86,8 @@ describe('graph', () => {
|
|||||||
expect(inst.get('group').get('id').endsWith('-root')).toBe(true);
|
expect(inst.get('group').get('id').endsWith('-root')).toBe(true);
|
||||||
|
|
||||||
const children = inst.get('group').get('children');
|
const children = inst.get('group').get('children');
|
||||||
expect(children.length).toBe(5);
|
expect(children.length).toBe(4);
|
||||||
expect(children[2].get('className')).toEqual('edge-container');
|
expect(children[1].get('className')).toEqual('edge-container');
|
||||||
expect(children[1].get('className')).toEqual('custom-group-container');
|
|
||||||
|
|
||||||
const nodes = inst.getNodes();
|
const nodes = inst.getNodes();
|
||||||
expect(nodes).not.toBe(undefined);
|
expect(nodes).not.toBe(undefined);
|
||||||
@ -1257,60 +1256,6 @@ describe('plugins & layout', () => {
|
|||||||
graph.destroy();
|
graph.destroy();
|
||||||
expect(graph.destroyed).toBe(true);
|
expect(graph.destroyed).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('graph animate', () => {
|
|
||||||
const graph = new Graph({
|
|
||||||
container: div,
|
|
||||||
height: 500,
|
|
||||||
width: 500,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node',
|
|
||||||
label: 'node',
|
|
||||||
groupId: 'g1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
groupId: 'g2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'g1',
|
|
||||||
title: 'cokkdl',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'g2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
||||||
|
|
||||||
graph.stopAnimate();
|
|
||||||
const isAnimating = graph.isAnimating();
|
|
||||||
expect(isAnimating).toBe(false);
|
|
||||||
|
|
||||||
graph.collapseGroup('g1');
|
|
||||||
|
|
||||||
let gnode = graph.findById('node');
|
|
||||||
|
|
||||||
expect(gnode.get('visible')).toBe(false);
|
|
||||||
|
|
||||||
const g2Node = graph.findById('node1');
|
|
||||||
expect(g2Node.get('visible')).toBe(true);
|
|
||||||
|
|
||||||
graph.expandGroup('g1');
|
|
||||||
|
|
||||||
timerOut(() => {
|
|
||||||
gnode = graph.findById('node');
|
|
||||||
expect(gnode.get('visible')).toBe(true);
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('auto rotate label on edge', () => {
|
describe('auto rotate label on edge', () => {
|
||||||
|
@ -92,10 +92,9 @@ describe('graph', () => {
|
|||||||
expect(inst.get('group').get('id').endsWith('-root')).toBe(true);
|
expect(inst.get('group').get('id').endsWith('-root')).toBe(true);
|
||||||
|
|
||||||
const children = inst.get('group').get('children');
|
const children = inst.get('group').get('children');
|
||||||
expect(children.length).toBe(5);
|
expect(children.length).toBe(4);
|
||||||
expect(children[2].get('className')).toEqual('edge-container');
|
expect(children[1].get('className')).toEqual('edge-container');
|
||||||
expect(children[1].get('className')).toEqual('custom-group-container');
|
|
||||||
|
|
||||||
const nodes = inst.getNodes();
|
const nodes = inst.getNodes();
|
||||||
expect(nodes).not.toBe(undefined);
|
expect(nodes).not.toBe(undefined);
|
||||||
expect(nodes.length).toBe(0);
|
expect(nodes.length).toBe(0);
|
||||||
@ -1007,66 +1006,6 @@ describe('plugins & layout', () => {
|
|||||||
graph.destroy();
|
graph.destroy();
|
||||||
expect(graph.destroyed).toBe(true);
|
expect(graph.destroyed).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('graph animate', () => {
|
|
||||||
const graph = new Graph({
|
|
||||||
container: div,
|
|
||||||
height: 500,
|
|
||||||
width: 500,
|
|
||||||
renderer: 'svg',
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node',
|
|
||||||
label: 'node',
|
|
||||||
groupId: 'g1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
groupId: 'g2',
|
|
||||||
x: 50,
|
|
||||||
y: 150,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'g1',
|
|
||||||
title: 'cokkdl',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'g2',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
||||||
|
|
||||||
graph.stopAnimate();
|
|
||||||
const isAnimating = graph.isAnimating();
|
|
||||||
expect(isAnimating).toBe(false);
|
|
||||||
|
|
||||||
graph.collapseGroup('g1');
|
|
||||||
|
|
||||||
let gnode = graph.findById('node');
|
|
||||||
|
|
||||||
expect(gnode.get('visible')).toBe(false);
|
|
||||||
|
|
||||||
const g2Node = graph.findById('node1');
|
|
||||||
expect(g2Node.get('visible')).toBe(true);
|
|
||||||
|
|
||||||
graph.expandGroup('g1');
|
|
||||||
|
|
||||||
timerOut(() => {
|
|
||||||
gnode = graph.findById('node');
|
|
||||||
expect(gnode.get('visible')).toBe(true);
|
|
||||||
graph.destroy();
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('auto rotate label on edge', () => {
|
describe('auto rotate label on edge', () => {
|
||||||
@ -2027,11 +1966,10 @@ describe('plugins', () => {
|
|||||||
graph.render();
|
graph.render();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const minimapGroup = minimap.get('canvas').get('children')[0];
|
const minimapGroup = minimap.get('canvas').get('children')[0];
|
||||||
expect(minimapGroup.get('children').length).toBe(5);
|
expect(minimapGroup.get('children').length).toBe(4);
|
||||||
graph.zoom(2, { x: 250, y: 250 });
|
graph.zoom(2, { x: 250, y: 250 });
|
||||||
|
|
||||||
expect(minimapGroup.get('children')[2].get('children').length).toBe(5);
|
expect(minimapGroup.get('children')[2].get('children').length).toBe(5);
|
||||||
expect(minimapGroup.get('children')[3].get('children').length).toBe(5);
|
|
||||||
const viewport = minimap.get('viewport');
|
const viewport = minimap.get('viewport');
|
||||||
expect(viewport.style.width).toBe('37.2093px');
|
expect(viewport.style.width).toBe('37.2093px');
|
||||||
expect(viewport.style.height).toBe('6.1794px');
|
expect(viewport.style.height).toBe('6.1794px');
|
||||||
@ -2583,174 +2521,3 @@ describe('plugins', () => {
|
|||||||
expect(parentDom).toBe(null);
|
expect(parentDom).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('custom group', () => {
|
|
||||||
const data = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
x: 150,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
x: 300,
|
|
||||||
y: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node7',
|
|
||||||
groupId: 'p1',
|
|
||||||
x: 200,
|
|
||||||
y: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node6',
|
|
||||||
groupId: 'bym',
|
|
||||||
label: 'rect',
|
|
||||||
x: 100,
|
|
||||||
y: 300,
|
|
||||||
type: 'rect',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node9',
|
|
||||||
label: 'noGroup',
|
|
||||||
x: 300,
|
|
||||||
y: 210,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const graph = new Graph({
|
|
||||||
container: div,
|
|
||||||
width: 500,
|
|
||||||
height: 500,
|
|
||||||
renderer: 'svg',
|
|
||||||
modes: {
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
type: 'collapse-expand-group',
|
|
||||||
trigger: 'click',
|
|
||||||
},
|
|
||||||
'drag-node-with-group',
|
|
||||||
'drag-group',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
it('render', () => {
|
|
||||||
graph.data(data);
|
|
||||||
graph.render();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('collapse-expand-group', () => {
|
|
||||||
const nodeGroup1 = graph.get('group').get('children')[1].get('children')[0].get('children')[0];
|
|
||||||
const hideNode1 = graph.getNodes()[0];
|
|
||||||
const hideNode2 = graph.getNodes()[1];
|
|
||||||
graph.emit('click', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
});
|
|
||||||
graph.once('click', () => {
|
|
||||||
expect(hideNode1.isVisible()).toBe(false);
|
|
||||||
expect(hideNode2.isVisible()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
graph.emit('click', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('drag-group', () => {
|
|
||||||
const nodeGroup1 = graph.get('group').get('children')[1].get('children')[0].get('children')[0];
|
|
||||||
const node1 = graph.getNodes()[0];
|
|
||||||
const node2 = graph.getNodes()[1];
|
|
||||||
const node1OriX = node1.getModel().x;
|
|
||||||
const node1OriY = node1.getModel().y;
|
|
||||||
const node2OriX = node2.getModel().x;
|
|
||||||
const node2OriY = node2.getModel().y;
|
|
||||||
graph.emit('dragstart', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
x: 50,
|
|
||||||
y: 50,
|
|
||||||
});
|
|
||||||
graph.emit('drag', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
x: 250,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
graph.emit('drag', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
x: 250,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
const delegateGroup = graph.get('delegateGroup');
|
|
||||||
expect(delegateGroup.get('children').length).toBe(1);
|
|
||||||
expect(delegateGroup.get('children')[0].attr('x')).toBe(325);
|
|
||||||
expect(delegateGroup.get('children')[0].attr('y')).toBe(200);
|
|
||||||
expect(node1.getModel().x).toBe(node1OriX);
|
|
||||||
expect(node1.getModel().y).toBe(node1OriY);
|
|
||||||
expect(node2.getModel().x).toBe(node2OriX);
|
|
||||||
expect(node2.getModel().y).toBe(node2OriY);
|
|
||||||
graph.emit('dragend', {
|
|
||||||
target: nodeGroup1,
|
|
||||||
x: 150,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
expect(delegateGroup.get('children').length).toBe(0);
|
|
||||||
expect(node1.getModel().x).not.toBe(node1OriX);
|
|
||||||
expect(node1.getModel().y).not.toBe(node1OriY);
|
|
||||||
expect(node2.getModel().x).not.toBe(node2OriX);
|
|
||||||
expect(node2.getModel().y).not.toBe(node2OriY);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('drag-node-with-group', () => {
|
|
||||||
const node3 = graph.getNodes()[2];
|
|
||||||
const node3OriX = node3.getModel().x;
|
|
||||||
const node3OriY = node3.getModel().y;
|
|
||||||
|
|
||||||
graph.emit('node:dragstart', {
|
|
||||||
target: node3,
|
|
||||||
item: node3,
|
|
||||||
x: 50,
|
|
||||||
y: 50,
|
|
||||||
});
|
|
||||||
graph.emit('node:drag', {
|
|
||||||
target: node3,
|
|
||||||
item: node3,
|
|
||||||
x: 350,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
graph.emit('node:drag', {
|
|
||||||
target: node3,
|
|
||||||
item: node3,
|
|
||||||
x: 350,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
const delegateGroup = graph.get('delegateGroup');
|
|
||||||
expect(delegateGroup.get('children').length).toBe(1);
|
|
||||||
expect(node3.getModel().x).toBe(node3OriX);
|
|
||||||
expect(node3.getModel().y).toBe(node3OriY);
|
|
||||||
|
|
||||||
graph.emit('node:dragend', {
|
|
||||||
target: node3,
|
|
||||||
item: node3,
|
|
||||||
x: 350,
|
|
||||||
y: 150,
|
|
||||||
});
|
|
||||||
expect(delegateGroup.get('children').length).toBe(0);
|
|
||||||
expect(node3.getModel().x).not.toBe(node3OriX);
|
|
||||||
expect(node3.getModel().y).not.toBe(node3OriY);
|
|
||||||
graph.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -114,7 +114,7 @@ describe('graph refactor states', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
it('compatible true/false states', () => {
|
it.only('compatible true/false states', () => {
|
||||||
const graph = new G6.Graph({
|
const graph = new G6.Graph({
|
||||||
container: div,
|
container: div,
|
||||||
width: 500,
|
width: 500,
|
||||||
@ -145,9 +145,8 @@ describe('graph refactor states', () => {
|
|||||||
graph.setItemState(item, 'hover', true);
|
graph.setItemState(item, 'hover', true);
|
||||||
graph.setItemState(item, 'select', true);
|
graph.setItemState(item, 'select', true);
|
||||||
});
|
});
|
||||||
graph.on('node:click', (e) => {
|
graph.on('node:mouseleave', (e) => {
|
||||||
const item = e.item;
|
const item = e.item;
|
||||||
|
|
||||||
graph.setItemState(item, 'hover', false);
|
graph.setItemState(item, 'hover', false);
|
||||||
graph.setItemState(item, 'select', false);
|
graph.setItemState(item, 'select', false);
|
||||||
});
|
});
|
||||||
@ -180,7 +179,7 @@ describe('graph refactor states', () => {
|
|||||||
expect(item.hasState('hover')).toBe(false);
|
expect(item.hasState('hover')).toBe(false);
|
||||||
expect(item.getStates()).toEqual([]);
|
expect(item.getStates()).toEqual([]);
|
||||||
expect(keyShape.attr('opacity')).toEqual(0.8);
|
expect(keyShape.attr('opacity')).toEqual(0.8);
|
||||||
graph.destroy();
|
// graph.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multivalued & muted', () => {
|
it('multivalued & muted', () => {
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
import { getAllNodeInGroups } from '../../../src/util/group';
|
|
||||||
|
|
||||||
describe('group util test', () => {
|
|
||||||
it('getAllNodeInGroups', () => {
|
|
||||||
const nodes = [
|
|
||||||
{
|
|
||||||
id: 'node1',
|
|
||||||
label: 'node1',
|
|
||||||
groupId: 'group1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node2',
|
|
||||||
label: 'node2',
|
|
||||||
groupId: 'group1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node3',
|
|
||||||
label: 'node3',
|
|
||||||
groupId: 'group2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node6',
|
|
||||||
groupId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'node6',
|
|
||||||
groupId: 'bym',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
nodes,
|
|
||||||
groups: [
|
|
||||||
{
|
|
||||||
id: 'group1',
|
|
||||||
title: 'group1',
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'group2',
|
|
||||||
title: 'group2',
|
|
||||||
parentId: 'p1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'bym',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'p1',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodesInGroup = getAllNodeInGroups(data);
|
|
||||||
expect(Object.keys(nodesInGroup).length).toBe(4);
|
|
||||||
const bym = nodesInGroup.bym;
|
|
||||||
expect(bym.length).toBe(1);
|
|
||||||
expect(bym[0]).toBe('node6');
|
|
||||||
|
|
||||||
const group1 = nodesInGroup.group1;
|
|
||||||
expect(Object.keys(group1).length).toBe(2);
|
|
||||||
expect(group1[0]).toBe('node1');
|
|
||||||
expect(group1[1]).toBe('node2');
|
|
||||||
|
|
||||||
const p1 = nodesInGroup.p1;
|
|
||||||
expect(Object.keys(p1).length).toBe(4);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user