g6/demos/layout-expand-nodes.html
2020-02-14 11:30:12 +08:00

649 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Expand Nodes with Force Layout</title>
</head>
<body>
<div id="mountNode"></div>
<script src="../build/g6.js"></script>
<script src="../build/force.js"></script>
<script src="./assets/d3-4.13.0.min.js"></script>
<script>
const getNodeById = {
success: true,
data: {
nodes: [
{
id: '20',
nodeType: 'Person',
label: 'name1',
properties: {
age: '37',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'M',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: 'name1',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1',
nodeType: 'Person',
label: 'name2',
properties: {
age: '31',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'FM',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: 'name2',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
],
edges: [
{
source: '20',
target: '1',
},
],
queryResult: '',
graphView: true,
},
errorCode: null,
msg: null,
};
// 根据节点扩展
const getNodesByNodeId = {
success: true,
data: {
nodes: [
{
id: '20',
nodeType: 'Person',
label: '祁同伟',
properties: {
age: '37',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'M',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '祁同伟',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '22',
nodeType: 'Person',
label: '高晓秦',
properties: {
age: '23',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '高晓秦',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '10',
nodeType: 'Person',
label: '高育良',
properties: {
age: '57',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'M',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '高育良',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '12',
nodeType: 'Person',
label: '高晓凤',
properties: {
age: '22',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '高晓凤',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '21',
nodeType: 'Person',
label: '梁璐',
properties: {
age: '40',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '梁璐',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '11',
nodeType: 'Person',
label: '吴淑芬',
properties: {
age: '50',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '吴淑芬',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '100',
nodeType: 'Enterprise',
label: '小米',
properties: {
IsChineseFunded: '',
businessScope: '',
credit: '',
employeesNumber: '0',
enterpriseNature: '',
establishmentTime: '',
holdingType: '',
importExportRightMark: '',
industryType: '',
isAdvantageEnterprise: '',
isLeadingEnterprise: '',
isOnBlacklist: '',
isOvercapacity: '',
isRegionalKeyEnterprise: '',
isSangaoEnterprise: '',
name: '小米',
registeredCapital: '0',
registrationAddress: '',
sbh: '',
size: '',
stockCode: '',
telephone: '',
},
},
{
id: '102',
nodeType: 'Enterprise',
label: '茅台',
properties: {
IsChineseFunded: '',
businessScope: '',
credit: '',
employeesNumber: '0',
enterpriseNature: '',
establishmentTime: '',
holdingType: '',
importExportRightMark: '',
industryType: '',
isAdvantageEnterprise: '',
isLeadingEnterprise: '',
isOnBlacklist: '',
isOvercapacity: '',
isRegionalKeyEnterprise: '',
isSangaoEnterprise: '',
name: '茅台',
registeredCapital: '0',
registrationAddress: '',
sbh: '',
size: '',
stockCode: '',
telephone: '',
},
},
],
edges: [
{
target: '100',
source: '20',
},
{
target: '102',
source: '20',
},
{
target: '10',
source: '20',
},
{
target: '11',
source: '20',
},
{
target: '21',
source: '20',
},
{
target: '21',
source: '20',
},
{
target: '22',
source: '20',
},
{
target: '11',
source: '10',
},
{
target: '12',
source: '10',
},
{
target: '22',
source: '21',
},
{
target: '22',
source: '12',
},
],
queryResult: '',
graphView: true,
},
errorCode: null,
msg: null,
};
// 根据节点扩展
const getNodesByNodeId2 = {
success: true,
data: {
nodes: [
{
id: '22',
nodeType: 'Person',
label: '高晓秦',
properties: {
age: '23',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '高晓秦',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1000',
nodeType: 'Person',
label: '晓秦1',
properties: {
age: '57',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'M',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '晓秦1',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1001',
nodeType: 'Person',
label: '晓秦2',
properties: {
age: '22',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '晓秦2',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1002',
nodeType: 'Person',
label: '晓秦3',
properties: {
age: '40',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '晓秦3',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1003',
nodeType: 'Person',
label: '晓秦4',
properties: {
age: '40',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '晓秦4',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
{
id: '1004',
nodeType: 'Person',
label: '晓秦5',
properties: {
age: '40',
annualIncome: '0',
career: '',
credit: '',
education: '',
email: '',
gender: 'F',
highestEducation: '',
isBusiness: '',
isOnBlacklist: '',
name: '晓秦5',
permanentResidenceAddress: '',
residentialAddress: '',
sbh: '',
telephone: '',
workUnit: '',
},
},
],
edges: [
{
target: '22',
source: '1000',
},
{
target: '22',
source: '1001',
},
{
target: '22',
source: '1002',
},
{
target: '1001',
source: '1002',
},
{
target: '1000',
source: '1',
},
{
target: '20',
source: '1002',
},
{
target: '22',
source: '1003',
},
{
target: '22',
source: '1004',
},
],
queryResult: '',
graphView: true,
},
errorCode: null,
msg: null,
};
let clickedNodeId = -1;
let clickedNodePos = {
x: 500,
y: 300,
};
// 封装点击添加边的交互
G6.registerBehavior('click-add-node', {
getEvents() {
return {
'node:click': 'onClick',
};
},
onClick(ev) {
const itemModel = ev.item.getModel();
clickedNodeId = itemModel.id;
clickedNodePos.x = itemModel.x;
clickedNodePos.y = itemModel.y;
const graph = this.graph;
const nodes = graph.getNodes();
const edges = graph.getEdges();
let newData = getNodeById.data;
if (itemModel.id == 20) newData = getNodesByNodeId.data;
else if (itemModel.id == 22) newData = getNodesByNodeId2.data;
let newNodeModels = newData.nodes;
let newEdgeModels = newData.edges;
let allNodeModels = [],
allEdgeModels = [];
// fix the existing nodes by set the fx and fy to the current value
// to cancel the fix the node, set fx = null fy = null
nodes.forEach((n, i) => {
const model = n.getModel();
model.fixed = true;
model.fx = model.x;
model.fy = model.y;
allNodeModels.push(model);
});
newNodeModels.forEach((nodeModel, i) => {
// if it does not exist in nodes
let exist = false;
nodes.forEach((n, i) => {
if (n.getModel().id == nodeModel.id) {
exist = true;
return;
}
});
// then add it into graph
if (!exist) {
// set the initial positions of the new nodes at the clicked node
nodeModel.x = itemModel.x;
nodeModel.y = itemModel.y;
const node = graph.addItem('node', nodeModel);
allNodeModels.push(nodeModel);
nodes.push(node);
}
});
newEdgeModels.forEach((em, i) => {
// if it does not exist in nodes
let exist = false;
edges.forEach((e, i) => {
const eModel = e.getModel();
if (eModel.source == em.source && eModel.target == em.target) {
exist = true;
return;
}
});
if (!exist) {
const edge = graph.addItem('edge', em);
edges.push(edge);
}
});
edges.forEach((e, i) => {
allEdgeModels.push(e.getModel());
});
graph.changeData({
nodes: allNodeModels,
edges: allEdgeModels,
});
},
});
let data = getNodeById.data;
const graph = new G6.Graph({
container: 'mountNode',
width: 1000,
height: 600,
layout: {
type: 'force',
center: [500, 300],
// 向心力作用点
nodeStrength: -30,
// 节点作用力
preventOverlap: true,
// 是否防止节点相互覆盖
nodeSize: 40,
// 节点大小 / 直径
edgeStrength: 0.1,
// 边的作用力, 默认为根据节点的入度出度自适应
linkDistance: 100,
// 默认边长度
},
modes: {
default: ['drag-node', 'click-select', 'click-add-node'],
},
defaultNode: {
size: [40, 40],
color: 'steelblue',
},
defaultEdge: {
size: 1,
color: '#e2e2e2',
},
});
graph.data(data);
graph.render();
graph.on('node:dragend', ev => {
const itemModel = ev.item.getModel();
itemModel.fixed = true;
itemModel.fx = ev.x;
itemModel.fy = ev.y;
});
</script>
</body>
</html>