<!DOCTYPE html style="width:100%;height:100%;">
<html>
<head>
<title>动态创建和编辑无向图</title>
<style>
#mynetwork {
width: 600px;
height: 400px;
border: 1px solid lightgray;
}
.btnClass{
margin: 5px;
padding: 5px;
}
.vr{
display: block;
height: 20px;
width: 1px;
border: 0;
background-color: black;
}
.label{
line-height: 2.5;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/vis-network/standalone/umd/vis-network.min.css" />
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
</head>
<body>
<div>
<div style="display: flex;">
<label for="nodeInput" class="label">节点:</label>
<input type="text" id="nodeInput" />
<button onclick="addNode()">添加节点</button>
<br />
<label for="fromInput" style="margin-left: 2em;" class="label">From点:</label>
<input type="text" id="fromInput" />
<label for="toInput" class="label"> ~ To点:</label>
<input type="text" id="toInput" />
<button onclick="addEdge()" class="btnClass" style="margin-left: 2em;">添加边</button>
<br />
<br />
<!-- 在HTML中添加删除按钮 -->
<button id="deleteButton" class="btnClass" >删除</button>
<button id="searchButton" class="btnClass" >查找</button>
<hr class="vr" />
<button onclick="generateRoute()" class="btnClass" style="margin-left: 2em;">生成路由</button>
</div>
<hr/>
<div style="display: flex;">
<label for="luyou" class="label">路由区:</label>
<textarea rows="10" id="route" style="min-heigth:600px;width:80%" ></textarea>
<button id="produceButton">生成无向图</button>
</div>
<hr/>
</div>
<div id="mynetwork" style="width:100%;height:90%;"></div>
<script>
const nodes = new vis.DataSet();
const edges = new vis.DataSet();
const container = document.getElementById('mynetwork');
const data = {
nodes: nodes,
edges: edges
};
const options = {};
var network = new vis.Network(container, data, options);
function addNode() {
const nodeValue = document.getElementById('nodeInput').value;
if (nodeValue) {
nodes.add({ id: nodeValue, label: nodeValue });
}
}
function addEdge() {
const fromNode = document.getElementById('fromInput').value;
const toNode = document.getElementById('toInput').value;
if (fromNode && toNode) {
edges.add({ from: fromNode, to: toNode });
}
}
function generateSql(data){
var sql="INSERT INTO `temp_point` (`node_name` ,`route`,`displayorder`) VALUES";
var temp="";
i=0;
Object.keys(data).forEach((key) => {
temp+="('"+key+"','["+data[key]+"]',"+i+"),";
i++;
})
sql=sql+temp.substring(0,temp.length-1);
console.log('~~~~~~~~~~~~',sql) ;
}
function generateRoute() {
const nodesArray = nodes.get();
const route = {};
nodesArray.forEach(node => {
const nodeId = node.id;
const edgesArray = edges.get({ filter: edge => edge.from === nodeId || edge.to === nodeId });
route[nodeId] = Array.from({ length: nodesArray.length }, (_, index) => {
const connectedNode = nodesArray[index].id;
return edgesArray.some(edge => (edge.from === connectedNode || edge.to === connectedNode) && nodeId !=connectedNode ) ? 1 : 0;
});
});
console.log('before~~~~~',route);
generateSql();
}
// 获取删除按钮和vis.js的节点和边
const deleteButton = document.getElementById('deleteButton');
// 监听删除按钮的点击事件
deleteButton.addEventListener('click', () => {
// 获取选中的节点和边
const selectedNodes = network.getSelectedNodes();
const selectedEdges = network.getSelectedEdges();
// 删除选中的节点
if (selectedNodes.length > 0) {
data.nodes.remove(selectedNodes);
}
// 删除选中的边
if (selectedEdges.length > 0) {
data.edges.remove(selectedEdges);
}
// 更新图表显示
network.setData(data);
});
// 监听查找按钮的点击事件
searchButton.addEventListener('click', () => {
var searchNodeInput = document.getElementById('nodeInput');
var searchValue = searchNodeInput.value;
if(searchValue==''){
alert('请输入节点关键字!');
return false;
}
// 在无向图中查找节点
var foundNode = data.nodes.get().filter(node => node.label.indexOf(searchValue)>-1 );
if (foundNode) {
data.nodes.update(data.nodes.get().map(node => ({
id: node.id,
color: '#97c2fc',
})));
for(var i=0,j=foundNode.length;i<j;i++){
var a= foundNode[i].label;
// 找到节点,将其标记为绿色
data.nodes.update(data.nodes.get().map(node => {
if( node.label === a){
return { id: node.id,
color: 'lime' };
}
}));
}
} else {
// 找不到节点,弹出警告框
alert('未找到节点!');
}
});
//根据路由产生无向图
produceButton.addEventListener('click', () => {
var data= document.getElementById('route').value;
var data=eval('('+data+')');
const tempNodes = Object.keys(data);
// const edges = [];
tempNodes.map((node) =>( nodes.add( { id: node, label: node })));
tempNodes.forEach((from, i) => {
for (let j = i + 1; j < nodes.length; j++) {
const to = tempNodes[j];
if (data[from][j] === 1) {
edges.add({ from: from, to: to });
}
}
});
if(network==null){
const graphData = {
nodes: tempNodes.map((node) => ({ id: node, label: node })),
edges: edges,
};
const options = {
layout: {
hierarchical: {
direction: "UD",
sortMethod: "directed",
},
},
edges: {
smooth: {
type: "cubicBezier",
},
},
};
network = new vis.Network(container, graphData, options);
}
});
</script>
</body>
</html>
以上代码是“无向图”的实现,要实现有向图,edges数组中对象元素加上‘arrows: 'to'’即可,
例如:{ from: 1, to: 2, arrows: 'to' }
演示效果:
无向图生成
最终路由格式:var data={A:[0,1,1,1,0],B:[1,0,1,0,1],C:[1,1,0,0,0],D:[1,0,0,0,0],E:[0,1,0,0,0]}
表示
规则:
data
对象中每个键值对的键表示一个点,键对应的值是一个一维数组,表示该点是否能分别到达其他点的路由。