我正在使用 vis.js 在网页上创建网络图。
我的需要是以 JSON 格式将操作图存储到数据库中,从网络图中导出 json。
我没有找到任何关于它的文档,是否可以使用操纵数据导出 vis.js 网络进行存储(以 JSON 或可转换为 JSON 的形式)?
我正在使用 vis.js 在网页上创建网络图。
我的需要是以 JSON 格式将操作图存储到数据库中,从网络图中导出 json。
我没有找到任何关于它的文档,是否可以使用操纵数据导出 vis.js 网络进行存储(以 JSON 或可转换为 JSON 的形式)?
至于data,这是我提取它以进行存储的 hacky 方法(我将尝试切断与问题无关的代码位):
// get nodes and edges
var nodes = network.body.data.nodes._data; // contains id, label, x,y, custom per-node options and doesn't contain options from options.nodes; presumably contains option values set when network was created, not current ones (it is so for x,y)
// network.body.nodes[id].nodeOptions shows options from options.nodes but not custom per-node options (same for edges and network.body.edges[id].edgeOptions)
// network.body.nodes contain much more stuff (x,y, default stuff)
//# look for a suitable getter
var edges = network.body.data.edges._data; // map; for edges to/from? certain node use network.getConnectedNodes(id)
// network.body.data.edges._data is a hash of { id: , from: , to: }
// get node positions
var positions = network.getPositions(),
nodeIds = Object.keys(nodes);
// get data describing nodes, edges and options for storage
var storedEdges = [], storedEdge, storedNodes = [], storedNode;
var indexIds = {}, idIndex = 1, end;
for(var nodeId in nodes) {
// nodes[nodeId].x is the initial value, positions[nodeId].x is the current one
if(positions[nodeId]) { // undefined for hidden
nodes[nodeId].x = positions[nodeId].x;
nodes[nodeId].y = positions[nodeId].y;
}
storedNode = copyObjectProperties(nodes[nodeId]);
// don't store id unless that breaks connected edges
if(!network.getConnectedEdges(nodeId).length)
storedNode.id = undefined;
// substitute generated ids with no semantics with simple indices
if(/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/.exec(storedNode.id)) {
while(nodes[idIndex])
idIndex++;
indexIds[storedNode.id] = idIndex; // remember the given index
storedNode.id = idIndex; // substitute with an index
idIndex++;
}
storedNodes.push(storedNode);
}
for(var edgeId in edges) {
storedEdge = copyObjectProperties(edges[edgeId]);
storedEdge.id = undefined; // then strip id
// change from/to in accord to the substitution above (for nodes' ids)
for(end of ["from","to"])
storedEdge[end] = indexIds[storedEdge[end]] || storedEdge[end];
storedEdges.push(storedEdge);
}
dataAndOptions = {
data: { nodes: storedNodes, edges: storedEdges },
options: storedOptions
};
var dataAndOptionsText = JSON.stringify(dataAndOptions,"",4)
.replace(/ {4}/gm,"\t").replace(/},\n\t\t\t{/gm,"},{");
和助手定义:
// helper for storing options
var copyObjectProperties = function(obj) {
return JSON.parse(JSON.stringify(obj));
};
有关更多上下文,请参阅我的 TiddlyWiki Classic 插件(saveDataAndOptions
方法)。这不是最新版本,但我会在某个时候更新它。
至于网络选项(如果他们被改变了),我还没有想出一个好的方法。
根据 Visjs 文档,您可能想要的方法是storePositions()
这是功能描述:
当使用 vis.DataSet 将节点加载到网络中时,此方法会将所有节点的 X 和 Y 位置放入该数据集中。如果您从数据库加载节点并将其与 DataSet 动态耦合,您可以使用它来稳定您的网络一次,然后通过 DataSet 将位置保存在该数据库中,以便下次加载节点时,稳定将接近瞬时。
如果节点仍在移动并且您正在使用动态平滑边缘(默认情况下启用),您可以使用物理模块中的选项 stable.onlyDynamicEdges 来缩短初始化时间。
此方法不支持聚类。目前,使用集群时无法缓存位置,因为它们无法仅从位置正确初始化。
用于storePositions()
将 X 和 Y 坐标加载到数据集。您可以将它们序列化,然后在稍后初始化网络时使用序列化坐标展开节点。
vis.js网络文档storePositions()
说:
当使用 vis.DataSet 将节点加载到网络中时,此方法会将所有节点的 X 和 Y 位置放入该数据集中。如果您从数据库加载节点并将其与 DataSet 动态耦合,您可以使用它来稳定您的网络一次,然后通过 DataSet 将位置保存在该数据库中,以便下次加载节点时,稳定将接近瞬时。
你必须DataSet
为你的network.data
. 要“保存”,只需调用network.storePositions()
它即可加载 X 和 Y 坐标,network.data.nodes
然后您可以根据需要对其进行序列化。
您只需forEach()
将network.data.nodes
序列化的 X 和 Y 坐标添加到其节点,然后通过update()
.
在此演示中,位置被序列化为textarea
. 您可以生成随机定位的图(这是默认行为),移动节点,序列化它们,可选择在 中编辑它textarea
,然后将其加载回来。
const nodes = [
{ id: 1, label: 1 },
{ id: 2, label: 2 },
{ id: 3, label: 3 },
{ id: 4, label: 4 },
]
const edges = [
{ id: '1-2', from: 1, to: 2 },
{ id: '1-3', from: 1, to: 3 },
{ id: '2-3', from: 2, to: 3 },
{ id: '1-4', from: 1, to: 4 },
]
const positionsElement = document.getElementById('positions')
const container = document.getElementById('graph')
const data = {
nodes: new vis.DataSet(nodes),
edges: new vis.DataSet(edges),
}
const options = {
layout: {
improvedLayout: false,
},
edges: {
smooth: false,
},
physics: false,
}
let network = null
function initGraph(generateRandomPosition = true) {
if (generateRandomPosition) {
data.nodes.forEach(node => {
data.nodes.update({ id: node.id, x: undefined, x: undefined })
})
}
network = new vis.Network(container, data, options)
}
document.getElementById('generate-graph').addEventListener('click', initGraph)
document.getElementById('extract-positions').addEventListener('click', e => {
network.storePositions()
const nodePositions = data.nodes.map(({ id, x, y }) => ({ id, x, y }))
positionsElement.value = JSON.stringify(nodePositions)
})
document.getElementById('load-positions').addEventListener('click', e => {
const nodePositions = JSON.parse(positionsElement.value)
nodePositions.forEach(nodePosition => data.nodes.update(nodePosition))
initGraph(false)
})
#graph {
width: 100%;
height: 300px;
border: 1px solid lightgray;
}
#positions {
width: 100%;
min-height: 60px;
}
<link href="https://visjs.github.io/vis-network/dist/vis-network.min.css" rel="stylesheet" />
<script src="https://visjs.github.io/vis-network/dist/vis-network.min.js"></script>
<div id="graph"></div>
<button id="generate-graph">Generate graph</button>
<button id="extract-positions">Extract positions</button>
<button id="load-positions">Load positions</button>
<textarea id="positions"></textarea>