fix: force layout overlap bug; add: tree and bubble leaves demo

This commit is contained in:
shiwu.wyy 2019-09-25 19:02:55 +08:00
parent 75869536dc
commit 9c7e8f8118
2 changed files with 303 additions and 0 deletions

View File

@ -0,0 +1,302 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dagre Layout</title>
</head>
<style>
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
<body>
<div id="mountNode"></div>
<script src="../build/dagre.js"></script>
<script src="../build/g6.js"></script>
<script>
const data = {
nodes: [{
id: '1',
label: '1'
},
{
id: '2',
label: '2'
},
{
id: '3',
label: '3'
},
{
id: '4',
label: '4'
},
{
id: '5',
label: '5'
},
{
id: '6',
label: '6'
},
{
id: '7',
label: '7'
},
{
id: '8',
label: '8',
isLeaf: true
},
{
id: '9',
label: '9',
isLeaf: true
},
{
id: '10',
label: '10',
isLeaf: true
},
{
id: '11',
label: '11',
isLeaf: true
},
{
id: '12',
label: '12',
isLeaf: true
},
{
id: '13',
label: '13',
isLeaf: true
},
{
id: '14',
label: '14',
isLeaf: true
},
{
id: '15',
label: '15',
isLeaf: true
},
{
id: '16',
label: '16',
isLeaf: true
},
{
id: '17',
label: '17',
isLeaf: true
},
{
id: '18',
label: '18',
isLeaf: true
},
{
id: '19',
label: '19',
isLeaf: true
}],
edges: [{
source: '1',
target: '2'
},
{
source: '1',
target: '3'
},
{
source: '3',
target: '4'
},
{
source: '2',
target: '5'
},
{
source: '5',
target: '6'
},
{
source: '5',
target: '7'
},
{
source: '7',
target: '8'
},
{
source: '6',
target: '9'
},
{
source: '6',
target: '10'
},
{
source: '6',
target: '11'
},
{
source: '6',
target: '12'
},
{
source: '6',
target: '13'
},
{
source: '6',
target: '14'
},
{
source: '4',
target: '15'
},
{
source: '4',
target: '16'
},
{
source: '4',
target: '17'
},
{
source: '4',
target: '18'
},
{
source: '4',
target: '19'
}]
};
const graph = new G6.Graph({
container: 'mountNode',
width: 1000,
height: 700,
modes: {
default: ['drag-node', 'drag-canvas']
},
defaultNode: {
shape: 'rect',// hexagon
color: 'steelblue'
},
defaultEdge: {
style: {
stroke: '#aaa'
}
}
});
const nodes = data.nodes;
const edges = data.edges;
const nodeMap = new Map();
const branchNodes = [];
const branchEdges = [];
const leafGroups = {};
const branchNodesMap = new Map();
const leafGroupOffset = 100;
// separate the leaves and branch nodes
nodes.forEach((node, i) => {
nodeMap.set(node.id, node);
if (node.isLeaf) {
node.size = 30;
node.shape = 'circle';
edges.forEach(edge => {
if (edge.source === node.id) {
node.parent = edge.target;
} else if (edge.target === node.id) {
node.parent = edge.source;
}
});
if (!leafGroups[node.parent]) leafGroups[node.parent] = [];
leafGroups[node.parent].push(node);
} else {
branchNodes.push(node);
branchNodesMap.set(node.id, node);
}
});
edges.forEach(edge => {
if (branchNodesMap.get(edge.source) !== undefined
&& branchNodesMap.get(edge.target) !== undefined) {
branchEdges.push(edge);
}
});
// layout the nodes with isLeaf === false by dagre
const dagreLayout = new G6.Layout['dagre']({
nodesep: 50,
ranksep: 10
});
dagreLayout.init({ nodes: branchNodes, edges: branchEdges });
dagreLayout.excute();
//layout the leaves with isLeaf === true by force
const forceLayoutsMap = new Map();
Object.keys(leafGroups).forEach(function(parentId){
const lg = leafGroups[parentId];
const parent = branchNodesMap.get(parentId);
const center = [ parent.x, parent.y + leafGroupOffset ];
const forceLayout = new G6.Layout['force']({
center,
linkDistance: 0,
nodeStrength: 50,
preventOverlap: true,
tick: () => {
graph.refreshPositions();
}
});
forceLayout.init({ nodes: lg, edges: [] });
forceLayout.excute();
forceLayoutsMap.set(parentId, forceLayout);
});
graph.positionsAnimate();
graph.data(data);
graph.render();
function refreshDragedNodePosition(e) {
const model = e.item.get('model');
model.fx = e.x;
model.fy = e.y;
}
graph.on('node:dragstart', e => {
const model = e.item.get('model');
if (model.isLeaf) {
const layoutMethod = forceLayoutsMap.get(model.parent);
layoutMethod.ticking = false;
layoutMethod.forceSimulation.stop();
layoutMethod.excute();
refreshDragedNodePosition(e);
}
});
graph.on('node:drag', e => {
const model = e.item.get('model');
if (model.isLeaf) {
refreshDragedNodePosition(e);
}
});
graph.on('node:dragend', e => {
const model = e.item.get('model');
if (model.isLeaf) {
e.item.get('model').fx = null;
e.item.get('model').fy = null;
}
});
</script>
</body>
</html>

View File

@ -110,6 +110,7 @@ Layout.registerLayout('force', {
* @param {object} simulation 力模拟模型 * @param {object} simulation 力模拟模型
*/ */
overlapProcess(simulation) { overlapProcess(simulation) {
const self = this;
let nodeSize = self.nodeSize; let nodeSize = self.nodeSize;
if (!nodeSize) { if (!nodeSize) {
nodeSize = d => { nodeSize = d => {