Skip to content Skip to sidebar Skip to footer

Visjs: Save Manipulated Data To Json

I am using vis.js to create network graphs on a web page. My need is to store manipulated graphs to a database in JSON format, exporting the json from the network graph. I did not

Solution 1:

As for data, here's my hacky way to extract it for storage (I'll try to cut off code bits irrelevant to the question):

// get nodes and edgesvar 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 gettervar 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 positionsvar positions = network.getPositions(),
    nodeIds = Object.keys(nodes);

// get data describing nodes, edges and options for storagevar 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 oneif(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 edgesif(!network.getConnectedEdges(nodeId).length)
        storedNode.id = undefined;
    // substitute generated ids with no semantics with simple indicesif(/\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,"},{");

and helper definition:

// helper for storing optionsvar copyObjectProperties = function(obj) {
    returnJSON.parse(JSON.stringify(obj));
};

For more context, see my plugin for TiddlyWiki Classic (saveDataAndOptions method). It's not the latest version, but I'll update it at some point.

As for network options (if they were changed), I haven't figured a nice way yet.

Solution 2:

According to Visjs documents, the method you might want is storePositions()

this is the the function description:

When using the vis.DataSet to load your nodes into the network, this method will put the X and Y positions of all nodes into that dataset. If you're loading your nodes from a database and have this dynamically coupled with the DataSet, you can use this to stablize your network once, then save the positions in that database through the DataSet so the next time you load the nodes, stabilization will be near instantaneous.

If the nodes are still moving and you're using dynamic smooth edges (which is on by default), you can use the option stabilization.onlyDynamicEdges in the physics module to improve initialization time.

This method does not support clustering. At the moment it is not possible to cache positions when using clusters since they cannot be correctly initialized from just the positions.

VisJs docs

Solution 3:

tl;dr

Use storePositions() to load the X and Y coordinates to your dataset. You can serialize them, then just expand the nodes with the serialized coordinates when you initialize the network later.

Explanation

The vis.js Network docs on storePositions() says:

When using the vis.DataSet to load your nodes into the network, this method will put the X and Y positions of all nodes into that dataset. If you're loading your nodes from a database and have this dynamically coupled with the DataSet, you can use this to stabilize your network once, then save the positions in that database through the DataSet so the next time you load the nodes, stabilization will be near instantaneous.

Saving

You have to use vis.js's DataSet for your network.data. To "save", just call network.storePositions() so it can load the X and Y coordinates to network.data.nodes then you serialize it however you want.

Loading

You just forEach() your network.data.nodes and add in the serialized X and Y coordinates to its nodes via update().

Example

In this demo, the positions are serialized into a textarea. You can generate randomly positioned graphs (that is the default behavior), move the nodes, serialize them, optionally edit it in the textarea, then load it back.

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 = nullfunctioninitGraph(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;
}
<linkhref="https://visjs.github.io/vis-network/dist/vis-network.min.css"  /><scriptsrc="https://visjs.github.io/vis-network/dist/vis-network.min.js"></script><divid="graph"></div><buttonid="generate-graph">Generate graph</button><buttonid="extract-positions">Extract positions</button><buttonid="load-positions">Load positions</button><textareaid="positions"></textarea>

Post a Comment for "Visjs: Save Manipulated Data To Json"