mirror of
https://gitee.com/antv/g6.git
synced 2024-11-30 02:38:20 +08:00
feat: dagre layout supports sortByCombo; feat: allow user to disable relayout in collapse-expand-combo behavior.
This commit is contained in:
parent
7b3d0d6f4d
commit
684cd874ec
@ -5,7 +5,9 @@
|
||||
- fix: dulplicated edges in nodeselectchange event of brush-select;
|
||||
- fix: triple click and drag canvas problem;
|
||||
- fix: sync the minZoom and maxZoom in drag-canvas and graph;
|
||||
- feat: initial x and y for combo data.
|
||||
- feat: initial x and y for combo data;
|
||||
- feat: dagre layout supports sortByCombo;
|
||||
- feat: allow user to disable relayout in collapse-expand-combo behavior.
|
||||
|
||||
#### 3.5.9
|
||||
- fix: multiple animate update shape for combo;
|
||||
|
@ -533,6 +533,10 @@ d => {
|
||||
|
||||
**Type**: Boolean<br />**Default**: false<br />**Required**: false<br />**Description**: Whether to enable the web-worker in case layout calculation takes too long to block page interaction
|
||||
|
||||
#### sortByCombo
|
||||
|
||||
**Type**: Boolean<br />**Default**: false<br />**Required**: false<br />**Description**: Whether to sort the nodes in a level according to the `comboId` in their data. Enable `sortByCombo` to avoid combo overlappings
|
||||
|
||||
### Function
|
||||
|
||||
The same as the superclass Layout, users do not need to concern about the function calling, which will be controlled by G6.
|
||||
|
@ -532,6 +532,12 @@ d => {
|
||||
|
||||
**类型**: Boolean<br />**默认值**: false<br />**是否必须**: false<br />**说明**: 是否启用 web-worker 以防布局计算时间过长阻塞页面交互
|
||||
|
||||
|
||||
#### sortByCombo
|
||||
|
||||
**类型**: Boolean<br />**默认值**: false<br />**是否必须**: false<br />**说明**: 同一层节点是否根据每个节点数据中的 `comboId` 进行排序,以防止 combo 重叠
|
||||
|
||||
|
||||
### 方法
|
||||
|
||||
与父类 Layout 的方法相同。使用该布局时不需要关心内部方法的调用,由 G6 控制。
|
||||
|
@ -155,7 +155,7 @@ To allow the users to interact with the combos, we implemented three built-in be
|
||||
|
||||
#### collapse-expand-combo
|
||||
|
||||
`'collapse-expand-combo'`behavior supports collapsing or expanding the combo by double clicking. The children will be hidden when the combo is collapsed, and the edges related to the children will link to the combo. If the graph has layout configuration, this behavior will trigger re-layout. If you do not want re-layout the graph after collapsing or expanding a combo, use combo's click listener and [graph.collapseExpandCombo API](/en/docs/api/Graph#collapseexpandcombocombo) instead.
|
||||
`'collapse-expand-combo'`behavior supports collapsing or expanding the combo by double clicking. The children will be hidden when the combo is collapsed, and the edges related to the children will link to the combo. If the graph has layout configuration and the `relayout` for this behavior is `true` (`true` by default), this behavior will trigger re-layout. If you do not want re-layout the graph after collapsing or expanding a combo, assign `relayout: false` for this behavior, or use combo's click listener and [graph.collapseExpandCombo API](/en/docs/api/Graph#collapseexpandcombocombo) instead.
|
||||
|
||||
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*X0_PSYizJ4AAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
||||
|
||||
|
@ -156,7 +156,7 @@ graph.render();
|
||||
|
||||
#### collapse-expand-combo
|
||||
|
||||
`collapse-expand-combo` Behavior,支持双击 Combo 收起和展开 Combo ,收起 Combo 以后,隐藏 Combo 中的所有节点,外部节点和 Combo 中节点有连线的情况下,所有连接会连接到 Combo 上面。若图配置有布局,则该 behavior 被触发后会触发图的重新布局。若希望避免重新布局,可以通过监听 combo 点击事件和 [graph.collapseExpandCombo API](/zh/docs/api/Graph#collapseexpandcombocombo) 控制收缩展开逻辑。
|
||||
`collapse-expand-combo` Behavior,支持双击 Combo 收起和展开 Combo ,收起 Combo 以后,隐藏 Combo 中的所有节点,外部节点和 Combo 中节点有连线的情况下,所有连接会连接到 Combo 上面。若图配置有布局且该 behavior 的 `relayout` 配置项为 `true`(默认为 `true`),则该 behavior 被触发后会触发图的重新布局。若希望避免重新布局,可以配置 `relayout` 为 `false` ,或通过监听 combo 点击事件和 [graph.collapseExpandCombo API](/zh/docs/api/Graph#collapseexpandcombocombo) 控制收缩展开逻辑。
|
||||
|
||||
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*X0_PSYizJ4AAAAAAAAAAAABkARQnAQ' width=400 alt='img'/>
|
||||
|
||||
|
@ -185,6 +185,8 @@ General graph layout API: [General Graph Layout API](/en/docs/api/layout/Graph).
|
||||
| ranksepFunc<br /><br /> | Function | d => {<br /> // d is a node<br /> if (d.id === 'node1') {<br /> return 100;<br /> }<br /> return 10;<br />} | undefined | The function for level separation with unit px. You can adjust the separations between different adjacent levels by using this function instead of `ranksep`. When `rankdir` is `'TB'` or `'BT'`, `ranksep` represents the vertical separations between adjacent levels; when `rankdir` is `'LR'` or `'RL'`, `rankdir` represents the horizontal separations between adjacent levels. The priority of `ranksepFunc` is lower than `ranksep`, which means if `ranksep` is assigned, the `ranksepFunc` will not take effect |
|
||||
| controlPoints | Boolean | true | true | Whether to keep the control points of layout |
|
||||
| workerEnabled | Boolean | true / false | false | Whether to enable the web-worker in case layout calculation takes too long to block page interaction |
|
||||
| sortByCombo | Boolean | true / false | false | Whether to sort the nodes in a level according to the `comboId` in their data. Enable `sortByCombo` to avoid combo overlappings |
|
||||
|
||||
|
||||
#### Concentric
|
||||
|
||||
|
@ -183,6 +183,8 @@ const graph = new G6.Graph({
|
||||
| ranksepFunc<br /><br /> | Function | d => {<br /> // d 是一个节点<br /> if (d.id === 'node1') {<br /> return 100;<br /> }<br /> return 10;<br />} | undefined | 层间距(px)的回调函数,通过该参数可以对不同节点设置不同的层间距。在`rankdir` 为 'TB' 或 'BT' 时是竖直方向相邻层间距;在`rankdir` 为 'LR' 或 'RL' 时代表水平方向相邻层间距。优先级低于 `ranksep`,即若设置了 `ranksep`,则 `ranksepFunc` 不生效 |
|
||||
| controlPoints | Boolean | true | true | 是否保留布局连线的控制点 |
|
||||
| workerEnabled | Boolean | true / false | false | 是否启用 web-worker 以防布局计算时间过长阻塞页面交互 |
|
||||
| sortByCombo | Boolean | true / false | false | 同一层节点是否根据每个节点数据中的 `comboId` 进行排序,以防止 combo 重叠 |
|
||||
|
||||
|
||||
#### Concentric
|
||||
|
||||
|
@ -66,7 +66,8 @@ Supported by V3.5 or later.
|
||||
- Description: collapse or expand Combo. If the graph has layout configuration, this behavior will trigger re-layout. If you do not want re-layout the graph after collapsing or expanding a combo, use combo's click listener and [graph.collapseExpandCombo API](/en/docs/api/Graph#collapseexpandcombocombo) instead;
|
||||
- Configurations:
|
||||
- `type: 'collapse-expand-combo'`;
|
||||
- `trigger`: Specify which key to hold for collapse and expand combo. `dblclick` by default. Options: `'click'`, `'dblclick'`.
|
||||
- `trigger`: Specify which key to hold for collapse and expand combo. `dblclick` by default. Options: `'click'`, `'dblclick'`;
|
||||
- `relayout`: Whether relayout the graph after collapsing or expanding, `true` by default.
|
||||
|
||||
**Default Configuration**
|
||||
|
||||
@ -85,7 +86,8 @@ const graph = new G6.Graph({
|
||||
modes: {
|
||||
default: [{
|
||||
type: 'collapse-expand-combo',
|
||||
trigger: 'click'
|
||||
trigger: 'click',
|
||||
relayout: false // do not relayout after collapsing or expanding
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
@ -66,7 +66,8 @@ V3.5 以上版本支持。
|
||||
- 含义:收起和展开 Combo。若图配置有布局,则该 behavior 被触发后会触发图的重新布局。若希望避免重新布局,可以通过监听 combo 点击事件和 [graph.collapseExpandCombo API](/zh/docs/api/Graph#collapseexpandcombocombo) 控制收缩展开逻辑;
|
||||
- 配置项:
|
||||
- `type: 'collapse-expand-combo'`;
|
||||
- `trigger`:触发方式,默认为双击收起或展示,可配置 click 和 dblclick。
|
||||
- `trigger`:触发方式,默认为双击收起或展示,可配置 `'click'` 和 `'dblclick'`;
|
||||
- `relayout`:收缩或展开后是否触发重新布局,默认为 `true`。
|
||||
|
||||
**默认配置**
|
||||
|
||||
@ -85,7 +86,8 @@ const graph = new G6.Graph({
|
||||
modes: {
|
||||
default: [{
|
||||
type: 'collapse-expand-combo',
|
||||
trigger: 'click'
|
||||
trigger: 'click',
|
||||
relayout: false // 收缩展开后,不重新布局
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
@ -10,7 +10,7 @@
|
||||
"zh": "两指平移画布",
|
||||
"en": "Drag Canvas by Two fingers"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*wc1-QaqOPsgAAAAAAAAAAABkARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eePLR7boe38AAAAAAAAAAABkARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
174
examples/net/dagreFlow/demo/dagreCombo.js
Normal file
174
examples/net/dagreFlow/demo/dagreCombo.js
Normal file
@ -0,0 +1,174 @@
|
||||
import G6 from '@antv/g6';
|
||||
const data = {
|
||||
nodes: [
|
||||
{
|
||||
id: '0',
|
||||
label: '0',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
label: '1',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: '2',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
label: '3',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
label: '4',
|
||||
comboId: 'A'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
label: '5',
|
||||
comboId: 'B'
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
label: '6',
|
||||
comboId: 'A'
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
label: '7',
|
||||
comboId: 'C'
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
label: '8',
|
||||
comboId: 'C'
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
label: '9',
|
||||
comboId: 'A'
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
label: '10',
|
||||
comboId: 'B'
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
label: '11',
|
||||
comboId: 'B'
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: '0',
|
||||
target: '1',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '2',
|
||||
},
|
||||
{
|
||||
source: '1',
|
||||
target: '4',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '3',
|
||||
target: '4',
|
||||
},
|
||||
{
|
||||
source: '2',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '1',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '1',
|
||||
target: '7',
|
||||
},
|
||||
{
|
||||
source: '3',
|
||||
target: '8',
|
||||
},
|
||||
{
|
||||
source: '3',
|
||||
target: '9',
|
||||
},
|
||||
{
|
||||
source: '5',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '5',
|
||||
target: '11',
|
||||
},
|
||||
],
|
||||
combos: [{
|
||||
id: 'A',
|
||||
label: 'combo A'
|
||||
}, {
|
||||
id: 'B',
|
||||
label: 'combo B'
|
||||
}, {
|
||||
id: 'C',
|
||||
label: 'combo C'
|
||||
}]
|
||||
};
|
||||
|
||||
let sortByCombo = false;
|
||||
const descriptionDiv = document.createElement('button');
|
||||
descriptionDiv.innerHTML = 'Enable sortByCombo';
|
||||
const container = document.getElementById('container');
|
||||
container.appendChild(descriptionDiv);
|
||||
|
||||
descriptionDiv.addEventListener("click", e => {
|
||||
sortByCombo = !sortByCombo
|
||||
descriptionDiv.innerHTML = sortByCombo ? 'Disable sortByCombo' : 'Enable sortByCombo';
|
||||
graph.updateLayout({
|
||||
sortByCombo
|
||||
});
|
||||
})
|
||||
const width = document.getElementById('container').scrollWidth;
|
||||
const height = document.getElementById('container').scrollHeight || 500;
|
||||
const graph = new G6.Graph({
|
||||
container: 'container',
|
||||
width,
|
||||
height: height - 50,
|
||||
linkCenter: true,
|
||||
fitView: true,
|
||||
fitViewPadding: 30,
|
||||
animate: true,
|
||||
modes: {
|
||||
default: [
|
||||
'drag-combo',
|
||||
'drag-node',
|
||||
{
|
||||
type: 'collapse-expand-combo',
|
||||
relayout: false
|
||||
}
|
||||
],
|
||||
},
|
||||
layout: {
|
||||
type: 'dagre',
|
||||
sortByCombo: false
|
||||
},
|
||||
defaultNode: {
|
||||
size: [30, 20],
|
||||
type: 'rect',
|
||||
},
|
||||
defaultEdge: {
|
||||
type: 'line',
|
||||
},
|
||||
defaultCombo: {
|
||||
type: 'rect'
|
||||
}
|
||||
});
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
|
@ -12,6 +12,14 @@
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*2uMmRo5wYPUAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "dagreCombo.js",
|
||||
"title": {
|
||||
"zh": "带有 Combo 的流程图",
|
||||
"en": "Dagre with Combos"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*94EUTJ8l2QAAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "lrDagreUL.js",
|
||||
"title": {
|
||||
|
@ -1,3 +1,3 @@
|
||||
// window.g6 = require('./src/index.ts'); // import the source for debugging
|
||||
window.g6 = require('./dist/g6.min.js'); // import the package for webworker
|
||||
window.g6 = require('./src/index.ts'); // import the source for debugging
|
||||
// window.g6 = require('./dist/g6.min.js'); // import the package for webworker
|
||||
window.insertCss = require('insert-css');
|
||||
|
@ -11,6 +11,7 @@ export default {
|
||||
getDefaultCfg(): object {
|
||||
return {
|
||||
trigger: DEFAULT_TRIGGER,
|
||||
relayout: true
|
||||
};
|
||||
},
|
||||
getEvents(): { [key in G6Event]?: string } {
|
||||
@ -31,7 +32,7 @@ export default {
|
||||
},
|
||||
onComboClick(evt: IG6GraphEvent) {
|
||||
const { item } = evt;
|
||||
const { graph } = this;
|
||||
const { graph, relayout } = this;
|
||||
|
||||
if (!item || item.getType() !== 'combo') return;
|
||||
const model = item.getModel();
|
||||
@ -40,7 +41,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
graph.collapseExpandCombo(comboId);
|
||||
if (graph.get('layout')) graph.layout();
|
||||
if (relayout && graph.get('layout')) graph.layout();
|
||||
else graph.refreshPositions();
|
||||
// graph.refreshPositions();
|
||||
},
|
||||
|
@ -2735,6 +2735,7 @@ export default class Graph extends EventEmitter implements IGraph {
|
||||
} else {
|
||||
this.collapseCombo(combo);
|
||||
}
|
||||
this.updateCombo(combo)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,8 @@ export default class DagreLayout extends BaseLayout {
|
||||
public ranksep: number = 50;
|
||||
/** 是否保留布局连线的控制点 */
|
||||
public controlPoints: boolean = false;
|
||||
/** 每层节点是否根据节点数据中的 comboId 进行排序,以放置同层 combo 重叠 */
|
||||
public sortByCombo: boolean = false;
|
||||
|
||||
public getDefaultCfg() {
|
||||
return {
|
||||
@ -107,6 +109,47 @@ export default class DagreLayout extends BaseLayout {
|
||||
edges[i].controlPoints = coord.points.slice(1, coord.points.length - 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (self.sortByCombo) {
|
||||
self.sortLevel('comboId');
|
||||
}
|
||||
}
|
||||
|
||||
public sortLevel(propertyName: string) {
|
||||
const self = this;
|
||||
const { nodes } = self;
|
||||
|
||||
const levels = {};
|
||||
nodes.forEach(node => {
|
||||
if (!levels[node.y]) levels[node.y] = { y: node.y, nodes: [] };
|
||||
levels[node.y].nodes.push(node);
|
||||
});
|
||||
|
||||
Object.keys(levels).forEach(key => {
|
||||
const levelNodes = levels[key].nodes;
|
||||
const nodesNum = levelNodes.length;
|
||||
if (nodesNum === 1) return;
|
||||
const sortedByX = levelNodes.sort((a, b) => { return a.x - b.x });
|
||||
const minX = sortedByX[0].x;
|
||||
const maxX = sortedByX[nodesNum - 1].x;
|
||||
const gap = (maxX - minX) / (nodesNum - 1);
|
||||
|
||||
const sortedByCombo = levelNodes.sort((a, b) => {
|
||||
const aValue = a[propertyName] || 'undefined';
|
||||
const bValue = b[propertyName] || 'undefined';
|
||||
if (aValue < bValue) {
|
||||
return -1;
|
||||
}
|
||||
if (aValue > bValue) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
console.log('sortedByCombo', sortedByCombo);
|
||||
sortedByCombo.forEach((node, i) => {
|
||||
node.x = minX + i * gap;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user