4

我正在使用 vis.js 在网页上创建网络图。

我的需要是以 JSON 格式将操作图存储到数据库中,从网络图中导出 json。

我没有找到任何关于它的文档,是否可以使用操纵数据导出 vis.js 网络进行存储(以 JSON 或可转换为 JSON 的形式)?

4

3 回答 3

2

至于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方法)。这不是最新版本,但我会在某个时候更新它。

至于网络选项(如果他们被改变了),我还没有想出一个好的方法。

于 2018-09-19T14:14:03.120 回答
1

根据 Visjs 文档,您可能想要的方法是storePositions()

这是功能描述:

当使用 vis.DataSet 将节点加载到网络中时,此方法会将所有节点的 X 和 Y 位置放入该数据集中。如果您从数据库加载节点并将其与 DataSet 动态耦合,您可以使用它来稳定您的网络一次,然后通过 DataSet 将位置保存在该数据库中,以便下次加载节点时,稳定将接近瞬时。

如果节点仍在移动并且您正在使用动态平滑边缘(默认情况下启用),您可以使用物理模块中的选项 stable.onlyDynamicEdges 来缩短初始化时间。

此方法不支持聚类。目前,使用集群时无法缓存位置,因为它们无法仅从位置正确初始化。

VisJs 文档

于 2017-04-20T06:14:50.480 回答
0

tl;博士

用于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>

于 2020-01-04T04:54:24.157 回答