mirror of
https://gitee.com/antv/g6.git
synced 2024-12-02 19:58:46 +08:00
638 lines
18 KiB
HTML
638 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> |